1) Shorten URL
2) Redirect Shortened URL
1) Scalable
2) Availability
3) Consistency
4) Durability
Redirect flow:
1) user hits the load balancer first to determine where to redirect the user
2) we are pointed to the redirect service
3) now we have the request in the redirect service
4) we fetch the short url key from the cache
5) if its not in the cache, we query the database for the long url
6) if it is found, reply to the http request with a 301 and the long url
7) update the cache with key- value of shorturl: longurl
Creation flow:
1) user hits load balancer
2) we are sent to the creation service
3) here we generate a short url for the long url
4) lets say we do a hash for the long url ~ and then enode it to base64 so that the url is alphanumeric then truncate to 8 characters if its more than that
5) we will try to insert this in the database, if it fails, because there is a unique constraint on the short url, we retry
Bottlenecks will come from the read path of our system. Meaning the cache and the database will be hit with a ton of traffic.
Both services are stateless, so it is easy to scale them by adding more servers.
1) Database consideration
2) Cache consideration
3) Load balancing
Explain any trade offs you have made and why you made certain tech choices...
1) We use a cassandra as our main analytics database since it can handle a lot of traffic for writes. Since it is write optimized, it is a lot better than a relational database since relational databases use b-trees and will have slower writes
2) Since we do sharding - we have to keep in mind that we cannot join easily. Since we dont really need to join any data, it is a good choice for us.
3) Since we do read replicas - we need to keep in mind the delay in updating the replicas. Since we have a cache that we update and since the first write is returned optimistically. it should be covered.
4) Since we have a few nodes/shards/replicas we need to know how to manage this system. A tool like Kubernetes, can be used to make sure our nodes are up and running.
1) The load balancer is a bottleneck and could fail. We will have a backup loads balancer who is passive. Traffic will be redirected to it in case the main load balancer fails
2) Nodes in the database and caches could fail. Since we are using Kubernetes, we rely on it to bring them back up.
3) Servers running the services could fail. Again, we rely on Kubernetes/or other orchestration software to revive the services.
3) We rely on Kubernetes and it could fail.
4) When a node in the Redis cluster fails, we could get a lot of cache misses. Since we use consistent hashing, we only get a minimal amount of keys that get affected since they are split in between the nodes and virtual nodes
5) Some database nodes could get too much traffic/data if the sharding is not done properly - a hot spot. We have to monitor this so that we can improve our key distribution. Sharding the large node should be enough to fix the issue temporarily.
1) Adding availability zones like east and west coast. Adding data centres in multiple continents to get closer to users. This can reduce the load of the system since we balance the load among regions. Doing this also improves availability since now even if datacenters or availability zones are down, we can redirect to other regions.
2) Improved algorithms when generating shortened URLS. Since currently we hash it our selves. There is no causality, it is hard to order the shortened URLs. For this we can use a technique like SnowFlake which integrates some of the bits in the returned value so we are able to have some order.
3) Using Terraform to manage the whole system. Since now there are a lot of moving parts, we need to use something that can make managing our system easier.
4) Using Redis Sentinel to manage our cache clusters can help us handle failure events.
We should expect around 1 million daily active users.
For traffic:
For throughput:
Storage:
generate_url
redirect_url
user_table
url_table
analytics_table
Components
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
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?