POST /shorten: Using the original URL generates a base62 hash version and stores it in both the cache and the database (write-through pattern)
GET /url: From the shortened version (parameter) obtains the original URL. We can use CDN to cache the most requested values.
There is a load balancer in front of the API servers to control spikes in its usage. These servers are stateless and auto-scale depending on the usage of the platform. Every server has a range of unique IDs from the ID generator.
For POST, the servers take the URL, create a unique ID associated with it, make the base62 conversion and store the shortened URL in the cache and the database. It is important to mention that the storage happens using the converted value as key so the GET endpoints works seamlessly (inverted with regards to the URL).
For GET, the shortened URL is used as a key to retrieve the whole URL from the cache.
The distributed cache uses an LRU eviction so we keep the most targeted URLs. TTL does not apply well here since it might convenient to keep records in cache that are obtained constantly. What makes sense is to limit the size of the cache.
When there is a miss, the URL is obtained from the SQL database and updates the cache. This will evict the LRU element from it, updating the cache.
There is no collision because base62 guarantees that (ID is unique since it comes from the generator). If the cache gets too many hits for a viral value we might use the same cache key in several nodes of the cache cluster using a random suffix to identify them.
Low latency is ensured since the LRU policy guarantees that the most requested URLs are the ones included in the cache. If a miss in the cache becomes viral all in a sudden, after that first miss it should be all hits due to the usage of this concrete URL.
If there are generator outages, the system keeps working because each server requested its range in advance.
Split-brain scenarios are prevented since a replica will be promoted to primary using quorum to ensure its election.