Given a long URL, it should return a short URL.
When a user goes to a shortened URL, it should redirect to the corresponding long URLs.
A URL can only map to one shortened URL.
Redirects should be done at high speed (a few milliseconds), and the service should have maximum uptime to prevent broken links.
The server should be able to handle a high volume of requests efficiently and be able to prioritize more commonly clicked links (hotspots).
The system will store tens of millions of link mappings, which requires a storage capacity of at most a few gigabytes of text data. Some links are clicked on more than others; let there be 1 million links being clicked a hundred times per day; that is about 10GB of bandwidth daily. The read/write ratio is very high, maybe 1000:1.
Only two important API endpoints in the backend:
POST /create
Inputs
link: The URL that the link should map to
alias (optional): An optional alias for the shortened URL.
This endpoint returns an error 409 if the alias is already taken and error 422 if it has prohibited characters, if the link field is missing, or if it does not have a valid link format.
If the request is successful, it returns the shortened URL, either with the alias or a randomly generated ending.
GET /link/{name}
Throws an error 404 if there is no link with the ending {name}, or if it is blank. Otherwise, it redirects to the corresponding long URL with code 302.
Since requests are stateless and uptime is a priority, the client makes requests to a load balancer. The only computation done on the server is calling the database and generating random links, allowing for horizontal scaling. To handle 1B requests per day, it is better to use a high-performance language like C or Rust and we need 20 or so backend servers.
Since certain links are clicked on much more than others, a cache is optimal for speed; Elasticache is one option. One possible caching scheme is LRU.
Due to the read-write rate asymmetry, a master-slave model for the database is best. Sharding is not necessary due to the small scale of data in each DB copy (<1 GB). In case of a cache miss, any slave is used for reading and the master is always used for writing.
The random link generation can be performed by generating a random number and appending the timestamp of when the request reaches the server and the ID of the specific server the request is being processed on, and hashing it. This reduces the risk of collision.s