Assume we have 1m shortening requests per day, let's assume 100:1 read/write ratio,
Traffic:
1m / 24 / 60 / 60 = 11.5 shortening requests per sec, and 100 * 11.5 = 1150 redirections per sec
Storage:
Assuming every request takes 1KB bandwidth, and we need to store 5 years data, this will take
1KB * 11.5 * 60 * 60 * 24 * 365 * 5 = 1729GB to store all data
Bandwidth:
For shortening, we assume 11.5 requests per second, so we need
11.5 * 1KB = 11.5KB/s
for read, 11.5 * 100 = 1150KB/s about 1MB/s
Memory: If we want to cache some of the hot URLs and follow 80-20 rule, meaning 20% urls get 80% traffic, we need
11.5 * 3600 * 24 =970MB, 970 * 0.2 = 194MB memory
POST createURL(apiDevKey, originalURL, expireDate=None, customAlias=None, userName=None)
GET getURL(apiDevKey, shortURL)
PATCH deleteURL(apiDevKey, shortURL)
User table
UserID PK
Name
CreationDate
LastLogin
URL table
Hash PK
OriginalURL
CreationDate
ExpirationDate
UserID FK
Since we are anticipating storing millions of URL objects and there is no relations between those URLs, we could use NoSQL store like DynamoDB or Cassandra.
Components:
Metadata storage: SQL store
Object store: DynamoDB
Application: URL shortening application server
Key generation server: to pre generate a uuid to avoid conflicts and improve system performance, this includes key generation service, key-DB.
load-balancer
Cache server: Redis
Cleanup service: we could run cron jobs to cleanup database in non-active time
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?