TinyURL: shorten long URLs to 7-char keys, redirect in <50ms p99. Core trick — pre-generated keys (KGS) + base62, shard by hash of short key, cache the hot 20%.
Every click hits origin. Enables counting + expiry.
Cache outcome
Hot 20% of keys serve ~80% of redirects.
Write QPS avg / peak
39 / 193
Read QPS avg / peak
386 / 1.9k
Storage (mappings)
~6.0 TB
+ replicas/indexes ≈ 3× raw
Origin QPS after CDN+cache
~386
302 tracked: every click hits origin
Cache hit ratio
95%
p99 < 10ms on hits
Keyspace (7-char base62)
0.3% used
62⁷ ≈ 3.5T keys — lasts decades
Test yourself
1. Why KGS instead of DB auto-increment?
Hosts mint from an in-memory range; the DB only hands out ranges. Single-writer bottleneck disappears.
2. When is 301 correct?
301 is cacheable forever. Anything with TTL/analytics must be 302 so origin enforces and counts.
3. How are DB shards chosen?
Lookups are always point queries, so hash sharding spreads perfectly with no range-scan cost.
4. Why no per-click MySQL write?
Redirect path does a bounded fire-and-forget send; batch jobs update MySQL hourly.
Drag nodes · scroll page normally · add ?elk to URL for auto-layout
Numbers that matter
Capacity is inside the flow above
Drag the sliders in the playground: 100M URLs/month ≈ 40 writes/s avg (200 peak),
10:1 reads, 500B records × 10 years ≈ 6TB. Flip 301 ↔ 302 and watch origin QPS swing —
that one toggle is the classic interview follow-up.
Deep dives
Key generation: counter vs hash vs KGS
Approach
Pros
Cons
Use when
Counter → base62
Simple, shortest
SPOF, leaks order
Prototype
Hash(longURL)
Stateless, free dedup
Collision loop, grinding
Dedup workloads
KGS ranges
No hot-path coordination
Tiny HA service
Production
Cache: Redis LRU + 60s negative-cache for 404s, singleflight on miss, TTL jitter against
stampedes. Analytics: redirect emits to Kafka, ClickHouse serves stats — MySQL counters
update hourly, never per click. First bottleneck at 10×: single Redis hot-key skew →
Cluster + client-side Caffeine in front.
Say it in the room
Interview one-liners
Q: Why not auto-increment? / A: Single-writer bottleneck; KGS = one DB op per 10k keys.
Q: 301 or 302? / A: 301 only for permanent untracked; TTL/tracked is 302.
Q: How do you shard? / A: Hash of short_key — point lookups, perfect spread.