Read-to-write ration: 100:1
1500 writes/s
11500 reads/sec
Average 2x for peaks = 3000 writes/s and 23000 reads/s
1TB of data/year
Two main APIs endpoint
POST - Request to create the short url
generateShortURL(long url, hash, created_at) - Rate limiter in a middleware
Returns 201 when created
GET - Redirect to the correct url
redirect(shortUrl)
returns 3xx status code
The write path runs about 1500 writes/s. Request arrives, the shortening service takes a key and one row is inserted
The read path runs at 20,000 requests per second, a hundred times heavier. A request arrives, the redirect service looks the key up, and returns a redirect.
Every write must get a key that no other write has ever used
For simplicity, we will have just one service - that creates de short url and that redirects - we dont need to scale both idependently.
The client will reach the API which communicates with cache and database
URL table
short_key - varchar(16)
original_url - varchar(2048)
created_at - timestamp
expires_at - timestamp
Load balancer distributes the traffic across all the server instances to improve resposiviness and availability. We may add an idle LB so LB is not a single point of failure.
The cache can be something like Redis to be served as an In Memory cache. The cache strategy should follow Lazy loading for read and write-around-cache for writes. We accept write-around since the data is written once and never updated and accept lazy loading since a cache failure should not break the system.
The database should be partitioned and replicated
We should partition the data by short key - take a hash of the key and map into N partitions. We should use consistent hashing to avoid issues on partitioning when adding/removing servers.
We can use a postgresql as database since we assume rigid schema