linkZapURL is a URL shortening service. It is a simple service that takes a long URL and returns a short URL. When a user visits the short URL, it will redirect to the long URL.
- Horizontal scalability (sharding, unique ID generator)
- Snowflake ID (timestamp + machineID + sequence) as unique ID
- Cache (including non-exist codes' requests)
- base58 encoding
Each document in the url
collection represents a tiny URL entity, structured as follows:
{
"ID": int64, // Unique ID generated by Snowflake algorithm
"shardID": int64, // Derived from `ID`, used for sharding
"url": string, // Actual URL
"expireAt": int64 // Expiration timestamp
}
Unique index: (shardID
, ID
).
Redis is used to cache the tiny URL entity. The key is the encoded ID
of the entity, and the value is the JSON string of the entity (URL and expiration timestamp).
- Converts a 64-bit integer to a base58 encoded string.
- Ensures output is up to 7 characters long.
- Converts a base58 encoded string (7 characters) back to a 64-bit integer.
All of the services are deployed in local machine for demonstration purpose. In production, the services should be deployed in different physical or virtual machines.
- MongoDB: database, shard
- Redis: cache, cluster
- Docker: container
- Docker Compose: container orchestration
- gin
- nginx: reverse proxy
My environment: WSL2
# Start MongoDB
cd ./docker/mongodb && ./init.sh && cd ../..
# Start Redis
cd ./docker/redis && ./init.sh && cd ../..
# Start Nginx
cd ./docker/nginx && ./init.sh && cd ../..
# Start Service
./init.sh
# Host: http://localhost
See config.yaml.
GET /swagger/index.html
-
POST /api/v1/shorten
Request Body:
{ "url": "<original_url>", "expireAt": "<expired_time>" // format: RFC3339 }
Response Body:
{ "id": "<code>", "shortUrl": "http://localhost/<code>" }
-
GET /:code
Redirect to the original URL