Design a URL Shortener (TinyURL / bit.ly)
mediumA URL shortener takes a long URL and returns a short alias; visits to the alias HTTP-redirect to the original. The interview value is in the classic distributed-systems skills it exercises: capacity estimation, key generation, read-heavy caching, and abuse defense at billions-of-rows scale.
Key Concepts
SHA256(url + salt)[:7] in base62 — idempotent (same URL → same key), collisions need retry. Production designs often mix: counter for auto-generated, reservation for custom aliases.SETNX).High-level design
Write path: client → API gateway → URL service → key generator → KV store → return short URL.
Read path: client → CDN/edge (cache check) → API gateway → URL service → KV store → 302 redirect.
Async: click events → Kafka → aggregator → analytics store.
Abuse: URL submission → safe browsing check → tag/block as needed.
Edge: CDN caches both the create response and the redirect.
Key generation
Counter-based: ZooKeeper/etcd hands out 1M-ID ranges to each shortener instance. Instance encodes counter to base62 (7 chars = 62^7 ≈ 3.5T). Predictable, mitigated by random shuffling or salt.
Hash-based: SHA256(url + salt)[:7] in base62. Idempotent — same URL gives same key. Collisions are rare but real; retry with extended hash or increment.
Hybrid (production-grade): batched ranges + hash for custom aliases.
Reservation for custom: conditional put — fail if taken.
Components
- API gateway with rate limiter (per IP, per API key).
- Key generator service (counter or hash).
- KV store (DynamoDB, Cassandra, or sharded Postgres) keyed by short alias.
- Edge cache (Cloudflare, Fastly) on the 302 redirect.
- Redis warm-tier cache for very hot links.
- Kafka + analytics pipeline (Spark / Flink → ClickHouse).
- Abuse / phishing filter (Safe Browsing API).
- Admin tools: revoke, expire, search.
Trade-offs
Counter vs hash: counter is predictable but coordinates well; hash is idempotent but collisions need retry.
301 vs 302: 301 caches more aggressively downstream (faster). 302 keeps requests flowing through your stack (better analytics, ability to change destination).
In-band vs async analytics: in-band is simple but slows the hot path. Async via Kafka is the production answer.
Sharded SQL vs KV: SQL gives joins and ad-hoc queries (helpful for ops); KV scales further with simpler ops.
Custom aliases vs auto-generated: customs need reservation; auto avoids collisions trivially.
Scale numbers
100M new URLs/day = 1200 writes/s sustained, ~30K/s peak.
1B reads/day = 12K reads/s sustained, ~1M/s peak.
Storage: 500 B/row × 100B rows × 10 yr = ~180 TB raw, ~500 TB with replicas. Easily holds in a 10-20 shard KV.
Cache hit rate (Zipfian): 5-10 GB of hot data handles 80%+ of redirects.
Common pitfalls
- Synchronous click count update on every redirect. Hammers the DB.
- 301 with frequently changing destinations. Downstream caches break the change.
- No abuse check on submission. Become a phishing relay overnight.
- Counter without sharding. Single global counter is a bottleneck.
- No edge cache on the redirect. Origin sees 100% of traffic.