The URL shortener is the classic first system design question. It looks simple but touches key-generation, storage, caching and read-heavy scaling — a perfect way to apply the framework.
1. Requirements
- Functional: shorten a long URL to a short one; redirect the short URL to the original; optional custom aliases and expiry.
- Non-functional: very read-heavy (many redirects per create), low-latency redirects, high availability, links effectively permanent.
2. Scale estimate
Say 100M new URLs/month and a 100:1 read:write ratio. That's ~40 writes/sec and ~4,000 redirects/sec — clearly read-dominated, which screams caching and replicas. Over 5 years that's ~6B URLs, so a 7-character key gives plenty of room.
3. Short-key generation
Encode a unique ID in base62 (a–z, A–Z, 0–9). 62⁷ ≈ 3.5 trillion combinations — more than enough. Two common approaches:
- Counter + base62 — a distributed unique ID (or ranges handed out to servers) encoded to base62. No collisions.
- Random / hash — generate a random 7-char key and check for collisions before saving.
4. Data model & storage
A simple mapping table: short_key → long_url, created_at, expiry, user_id. Because it's just key lookups at huge scale, a key-value / NoSQL store fits well, though SQL works at moderate scale. The dataset shards cleanly on the short key.
5. The redirect path (make it fast)
A redirect is a read: look up the key, return a 301/302 to the long URL. Put a cache (Redis) in front of the DB — the hot links serve almost entirely from cache. Add read replicas and a CDN edge for global low latency.
6. Bottlenecks & extras
Discuss: unique ID generation without collisions, cache invalidation on expiry, analytics via an async queue (don't block the redirect to count clicks), and abuse/spam protection with rate limiting.