An open API service indexing awesome lists of open source software.

https://github.com/zhima-mochi/linkzapurl

System design for URL shortener service.
https://github.com/zhima-mochi/linkzapurl

docker docker-compose golang mongodb-sharding nginx redis-cluster system-design

Last synced: 4 months ago
JSON representation

System design for URL shortener service.

Awesome Lists containing this project

README

          

# linkZapURL - System Design for URL Shortener Service

## Table of Contents
- [Introduction](#introduction)
- [Features](#features)
- [Architecture](#architecture)
- [High Level Design](#high-level-design)
- [Final Architecture](#final-architecture)
- [API Sequence Diagram](#api-sequence-diagram)
- [Shortening Service](#shortening-service)
- [Redirection Service](#redirection-service)
- [Tech Stack](#tech-stack)
- [Run](#run)
- [Endpoints](#endpoints)
- [Swagger](#swagger)
- [linkZapURL Service](#linkzapurl-service)

## Introduction
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.

## Features
- Horizontal scalability (sharding, unique ID generator)
- Snowflake ID (timestamp + machineID + sequence) as unique ID
- Cache (including non-exist codes' requests)
- base58 encoding

## Architecture

### High Level Design
![High Level Design](./docs/design/High_Level_Design.jpeg)

### MongoDB Schema Design for URL Collection

Each document in the `url` collection represents a tiny URL entity, structured as follows:

```bash
{
"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 key-value Design for Cache

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).

### Base58 Encoding Functions

#### `Encode(num int64) string`
- Converts a 64-bit integer to a base58 encoded string.
- Ensures output is up to 7 characters long.

#### `Decode(code string) int64`
- Converts a base58 encoded string (7 characters) back to a 64-bit integer.

### Final Architecture
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.

![Final Design](./docs/diagrams/linkzapurl_architecture.png)

## API Sequence Diagram
### Shortening Service

![Shortening Service Sequence Diagram](./docs/design/Shortening%20Service/sequentialDiagram.jpeg)

### Redirection Service

![Redirection Service Sequence Diagram](./docs/design/Redirection%20Service/sequentialDiagram.jpeg)

## Tech Stack
- [MongoDB](https://www.mongodb.com/): database, shard
- [Redis](https://redis.io/): cache, cluster
- [Docker](https://www.docker.com/): container
- [Docker Compose](https://docs.docker.com/compose/): container orchestration
- [gin](https://github.com/gin-gonic/gin)
- [nginx](https://www.nginx.com/): reverse proxy

## Run
My environment: WSL2
```bash
# 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
```

### Configurations
See [config.yaml](./docker/config.yaml).

## Endpoints

### [Swagger](./docs/swagger.json)
- `GET /swagger/index.html`

### linkZapURL Service
- `POST /api/v1/shorten`

Request Body:
```bash
{
"url": "",
"expireAt": "" // format: RFC3339
}
```

Response Body:
```bash
{
"id": "",
"shortUrl": "http://localhost/"
}
```
- `GET /:code`

Redirect to the original URL