optional:
editUrl(user_id. short_url, long_url)
On the high level, the user communicate with the apps servers through a load balancer.
The read requests goes through a in memory cache for quick retrieval. In case of miss, the cache fetches the data from a distributed key value store.
On writes, the request is passed to a url manager that create the mapping.
URL worker: on a write request, the long_url is sent to a url worker (from a cluster of them). The url worker load in memory a range of url from the available url database (which is sql for ACID properties). The urls are set to used at this point and no other worker can get them. The URL generator fills the database with new short_url when needed. The url worker verify the auth fo the user, and if good, write to the key value store master node the new mapping short_url:long_url with the ttl. The data will be eventually replicated to the read replicas
Redis cache: The redis cache is on the read path. On read request, the url retriever checks for the presence of the mapping in the cache, and it gets returned fast if there. Else, the cache query a read replica of the key value store and update the cache. Cache eviction policy should be least recently used. As the key value pair are small, we can have a consequent portion of the keys in memory for quick access
The cache ttl is also shorter to avoid long lasting wrong redirects and cache refresh. The caches can be replicated and geodistibuted