Extension:
We expect our design to be read heavy, we will assume an 100:1 read to write ratio. Let's assume we have 100 mil new URL shortenings per month, then we will have 500 mil redirects per month.
Traffic estimate:
Storage est:
Bandwidth Est:
Memory: We probably want to cache the 20% most popular short URLs for redirects, since we read around 3000 per second, thats around 3000 * 10 ^ 5 per day. 3 * 10^ 8 * 500 bytes * 0.2 = 3 * 10^10 = 30 GB
If we have servers that can take around 8000 requests per second, with around 3 million writes and 300 million reads per day, we expect around 37500 servers needed
dev key ensures we adhere to quotas for the given user
We consider that:
We expect the schema to look like the following:
We will opt to use a no sql for the storage of short urls and the users table given there is not many relations. Something like mongoDB will be good here for consistency in writes and its suitable for read heavy operations
We can consider range based query or hash based sharding for the database, to prevent bottle necks, we can go with consistent hashing on the keys
In the encoding of the URL, we will use an offline key generation service. This keeps track of a used and unused key table. When it delegates keys to the servers, it moves the keys to the used key table. We will be generating keys of length 6, it will use a distributed lock to ensure it does not give a key to multiple servers. We will also keep a backup KGS in case of disaster mitigation or KGS failure. When KGS dies, the backup takes over to continue generate the keys.
We can add caches to multiple places, such as a db cache for faster lookup. We will use LRU eviction policy here since popular urls will be used more recently. Each cache entry holds the short to long URL mapping.
We can also cache at the app server, the KGS will send over some keys to the server, after it marks it as used. Then the server can use the values in the cache.
In case of a cache miss, we fetch from the backend db, then replicate the values to each cache.
We can also add load balancers between the client and the app server, app server and the database and the cache servers. We could use round robin or more advanced algorithms to detect heavy/light loads
Creating a new url:
Redirect:
Deletion:
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Explain any trade offs you have made and why you made certain tech choices...
Try to discuss as many failure scenarios/bottlenecks as possible.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?