The system should accept long URLs from users and return short ones. When visited, the short URL redirects to the long URL. It expires after 30 days by default or by another period of time if explicitly pointed by users.
Latency: <100ms
Scalability: supports millions of URLs and 100000 thousands of reads/sec
Availability: 99.95% uptime. Redirects must never fail.
Durability: mappings are never lost
Security: block phishing URLs, SQL injections, list of all links.
100M new URLs each day
500M daily active users
They generate 10B redirects
Read to write ratio: 100/1
Daily reads: 10B
Storage requirements: 500b/URL -> 50GB per day
Assuming 2x YoY growth: ~100TB by end of year 1, ~200TB by year 2 — mitigated by TTL-based cleanup of expired links.
POST /create body {'url': ""}- creates a short URL from a long one
Invalid URLs return 400
GET /{short_url} - gets a long URL from the short one
invalid input returns 400
expired links return 410
LIST / - lists all urls by user to them only
unauthorized access returns 403
User submits a long URL -> the client sends it to the server -> shortener service generates a unique short code -> checks for the uniqueness and regenerates if it is not unique -> it records it to the database -> returns it.
User click a short URL -> client sends it to the redirect service -> checks cache -> if miss, checks the DB -> returns the long URL -> redirects to the long URL with 302
Schema:
NoSQL Database (Mongo) + caching Database (Redis)
{
short_code: string - unique index, partition key
long_url: string
created_at: datetime
expires_at: datetime
}
write consistency: two users cannot get the same code
read consistency: can be eventual, so one can get 404 if it is not written yet
Short code generator: accepts a long url, gets a random base62 code for uniqueness, checks if the short code is already in the database, and if it exists, retries. Otherwise returns the short code. The mapping table is sharded bu hash (short_code) % N.
Caching layer - Redis based on the volatile-lru policy - it is basically TTL with the 7 days expiration date, bit during spikes in turns to LRU. It absorbs hot links so no single shard gets overloaded.
GET service: takes a short code, searches in the cache. When the cache fires, it returns the short code. if it misses, it tries to get data from the DB. If there is no data in the DB, it returns 404. Then it redirects with 302. Every redirect routes to exactly one shard depending on short_code.
Security. When admins disable/flag a link, it is deleted from Redis and the shard. Creation has rate limiting.
Failure scenarios:
If Redis dies, reads fall back to the DB.
If one shard fails, replicas take over.