design bitly
Problem goes like this…
Functional Requirements
We want to design a system that primarily does URL-shortening… the system must support the following requirements
- Submitting a URL should return a shortened version of the URL.
- Shortened URLs can also be aliased or expired after a specified date.
- Users should be able to access the original URL through the shortened URL.
Non-Functional Requirements
We want to first decide whether we want our system to be consistent vs available, as in if one user submits a URL and receives that shortened URL, that shortened URL should work throughout all systems. Availability means that our service should prioritize always being online. Since this is a URL shortener, I believe that being consistent is much more important.
Core Entities
-
(URL Entity) So want a way to represent a shortened URL, perhaps a map of the provided url vs the actual url.
- We also want a way to alias shortened URLs.
API
-
POST /url -> strCreates a unique shortened URL from the original URL.{
original_url : str,
alias: str | null,
expiration: datestring | null
} -
GET /url/{shortened_url}redirects the client to the intended URL destination works with aliases. -
PATCH /url/{shortened_url}{
alias : str | null,
expiration: datestring | null
}
High-Level Design
The client submits a URL to the URL Shortening Service, which writes a new URL Entity (original URL, shortened URL, alias, expiration) to the Database. It generates a unique hash for the URL and checks the database for a collision before inserting, assigning an index on every insert to keep lookups fast. On redirect, the service checks the Redis Cache first; only the first redirect for a given shortened URL or alias misses the cache and falls through to the Database, and every redirect after that is served from Redis.
Some key takeaways is that…
- Horizontal scaling will enable processing more read requests per second.
- Add caching on a very read heavy system will be useful like a redis cache that will be populated on the first redirect request for a specific url.
- To enforce uniqueness, we might want something like a counter then encode it using base62 so the urls are short.
- Typically we should separate out the API from the services from the database.