Requirements
Functional Requirements:
- Create a short URL for a given long URL.
- Return the long URL associated with a given short URL.
Non-Functional Requirements:
- latency
- high availability (99.99%)
- scalability
API Design
Post /shorten
Body: {long_url}
Response: {short_url}
Get /url/{short_url}
Response: 301/302 for redirect
High-Level Design
Architecture:
- Service-oriented with independently scaling services
- stateless services, each running multiple instances
- all services emit telemetry
Entity Data Models:
ShortUrl:
id (pk)
short_url (unique, indexed)
long_url (unique, indexed)
created_at
updated_at
Detailed Component Design
Redirect service
- check if the short url is cached
- on cache hit it redirects the user to the long url
- on cache miss it fallsback to reading the db, and if the url exist it writes it to cache and redirects the user
Shortening Service
- check if long url already exist in db, if it does it returns the short_url for it
- if it's a new long_url, it base encodes the url into a short version
- stores the short url into the db
- adds the short url to cache, to get it ready for use
- returns the generated short url back to the user
DB
- uses synchronous replicas for strong consistency & fault tolerance
- primary db for writes, reads from replicas
- For horizontal scaling, the db can be sharded using the short url id as the hash key, and consistent hashing. This way the number of shards can be increased or decreased with minimal remapping required.