1) Shorten URL
2) Redirect Shortened URL
1) Scalable
2) Availability
3) Consistency
4) Durability
We should expect around 1 million daily active users.
For traffic:
For throughput:
Storage:
generate_url
redirect_url
Defining the system data model early on will clarify how data will flow among different components of the system. Also you could draw an ER diagram using the diagramming tool to enhance your design...
user_table
url_table
analytics_table
Components
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.
5) We also need to discuss how our databases handle partition events. Like in primary/secondary where have promote a secondary node to a primary. Voting mechanisms to who should be the new primary. How data is replicated among nodes. So we can gracefully recover from the backups/replicas.