List functional requirements for the system (Ask the chat bot for hints if stuck.)...
List non-functional requirements for the system...
Estimate the scale of the system you are going to design...
data size:
write QPS: 200 Tiny URL generations/ Second
Peak Write QPS: 400/ sec
Read QPS: 20000 requests / Second
Peak Read: 40000/sec
The average time we save the URL is 5 years. The long of the URL is 100 bytes, short will be 20 bytes;
So per URL we need 120 bytes storage.
Each day we generate 200 * 3600 * 24 ~= 16 M
Five years we generate 16 M * 365 * 5 ~= 4 B
Storage we need for total : 120 bytes * 4 B requests = 400 GB
Define what APIs are expected from the system...
Write API:
POST /api/shorternURL
body {"url": "www.google.com"}
Response:
{"tinyURL": "/api/{TinyURL}", "expiredTime": "2032-02-99"}
Read URL:
GET /api/{TinyURL}:
status code: 301 (redirect)
Response:
LongURL for HTTP redirection
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...
We store the Original URL as key, {"OriginalURL": {"ShortenURL": "ExpiredData"}}
And Also: {"ShortenURL": {"OriginalURL": "ExpiredData"}} For user to retrieve the originalURL
You should identify enough components that are needed to solve the actual problem from end to end. Also remember to draw a block diagram using the diagramming tool to augment your design. If you are unfamiliar with the tool, you can simply describe your design to the chat bot and ask it to generate a starter diagram for you to modify...
User will send to shortenService to get shorten URL, and we will check if the the original URL exist, we will notify this original URL already exist, and return the shorten URL. Else, we will generate the short URL and write to database and return to user the shorten URL.
When user use shorten URL to fetch long URL, user will visit shorten service that we will fetch the long URL with shorten URL. And then return the original URL and redirect user to the original URL. Because in this system, user read more than write so we could have a cache between shorten service and database, so the frequently used URL, we could cache that into the cache.
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...
User will send to shortenService to get shorten URL, and we will check if the the original URL exist, we will notify this original URL already exist, and return the shorten URL. Else, we will generate the short URL and write to database and return to user the shorten URL.
When user use shorten URL to fetch long URL, user will visit shorten service that we will fetch the long URL with shorten URL. And then return the original URL and redirect user to the original URL. Because in this system, user read more than write so we could have a cache between shorten service and database, so the frequently used URL, we could cache that into the cache.
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...
For the shorten Service, we could use the hash function to transfer the longURL to shortURL. LIke CRC32, MD5, SHA-1.
For the database, we could use Redis or DynamoDB, they are key values store, Non SQL, which is famous for fast retrieve performance, good for key value pair store.
And shortenservice is stateless service, if we need to scale in future, we could easy to scale out by adding more services. We could add loadbalance before shorten service. So when the requests came to load balancer. Loadbalaner could easily evently distributed traffic to different service.
Explain any trade offs you have made and why you made certain tech choices...
We could use SQL as database, and put a cache before SQL, for read purpose. However, SQL is not good for scale out. Therefore, nosql database will be a good choice. Redis, DynamoDB will be a good choice.
We move the database out of the service, because we want shorten service could scale easier.
Try to discuss as many failure scenarios/bottlenecks as possible.
If the shorten service break, loadbalancer will notice and load balancer will not direct the traffic to the crush service, instead, load balancer will send the request to the new service.
However, if a request has not been handled, we could not process it, because we have not save it anywhere. so in this case, user need to resend the request.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?
We could add a message queue between loadbalancer and shorten Service to make sure the shorten URL will be write to database exactly once. and when there is crash in shortenservice, another worker could take the job (status not finish ) to continue the job.