Requirements
Functional Requirements:
- Create a short URL for a given long URL.
- Return the long URL associated with a given short URL.
Non-Functional Requirements:
- high availability
- redirect in < 10ms
- scalable in storage capacity
Capacity Estimation
- 100 reads for each 1 write (considering the URLs to shorten are not too famous
API Design
Rest API: GetTinyURL
- input: original URL
- output: tiny URL
Rest API: GetOriginalURL
- input: tiny URL
- outpur: original URL
High-Level Design
User will communicate with a gateway API that redirect to one of the APIs described above. The GetTinyURL directs to the ShrinkUrlService, which will save the long and tiny urls. The GetOriginalURL directs to the UrlService, which will return the long url, given the tiny one.
Database Design
ShrinkUrlService, we'll use a relational database configured with sharding split by country.
Each tinyed URL will have the domain name plus unique key, plus a sequencial number, separated by a "-". Like this: mydomain.com/UNIQUEKEY-1.
So the databse will have 2 tables. In the first one, the primary key is the tiny url's unique key, and it has a column with a list of numbers (the sequential numbers from the end of URL. The second one maps these sequential number to the original URL
The UrlService will use read replicas of these writing databses. It can easily consult the list of URLs for the unique key from the tinyURL, them distinguish it by the sequential number.
Detailed Component Design
ShrinkUrlService: generate a hash key using MD5 that will be used as the unique key in the URL and in the database. I then checks if there is hash collision, if it is, increment the sequential number for it. Saves everything on databse and return the tiny URL
UrlService: Given the tiny URL, queries the database to find the unique key. Once found, check if it has multiple sequential numbers. If so, query it on the second table. return the found original URL. This will be reading from a read replica, so we don't get blocked by the writings