The Runtime Theory
hardawesome-system-design#high-level-design#scalability#caching

Design URL Shortener

Design a URL shortening service handling 100M new URLs per day: base62 IDs, write-through cache, and a KV store fronting sharded MySQL.

The Runtime Theory Team1 min read
Solve it

solving happens on the judge — come back and mark it done

Sample cases

in100M new URLs per day

out~1.2K writes/sec; ~115K reads/sec at 100:1 read:write

in10 years of mappings at 100 bytes each

out~3.7TB — one sharded MySQL cluster

in1M QPS read spike

outRedis cache absorbs it at 80% hit rate; DB sees ~200K QPS

incollision on generated ID

outregenerate; 62^7 ≈ 3.5T keys makes it ~never

The service maps a long URL to a short code and back. Functional requirements: shorten (POST), redirect (GET), custom aliases, expiry, and click analytics. At 100M new URLs per day the machine must sustain ~1,160 writes/sec average and, at a 100:1 read:write ratio, ~115K reads/sec — peaking multiples higher in business hours.

The ID is the core decision. The machine reserves the ID first — a ticket from a distributed ID generator or a DB auto-increment — then encodes it in base62 ([a-zA-Z0-9]), so 7 chars cover 62^7 ≈ 3.5 trillion URLs. No hash-and-check loop needed; the mapping is bijective. Redirects are read-mostly, so the hot path is: check Redis by code, on miss read MySQL, populate cache with TTL, 301 to the long URL.

Components: stateless API servers behind a load balancer; Redis for the read cache; MySQL sharded by code hash for the mapping table; an async worker that consumes a Kafka topic of shorten events to build analytics (per-code click counts, referrers, geo).

Data model: one table, mappings(code PK, long_url, user_id, created_at, expires_at), plus a clicks aggregate table written by the analytics worker. The cache stores code → long_url only; nothing else needs sub-millisecond reads.

Bottlenecks: DB write throughput during bursts (mitigate with batch inserts and a write buffer queue); cache stampede on cold keys (use single-flight or short randomized TTLs); base62 decode must handle 7-char codes with leading zeros correctly — the code is a number, not a string. Analytics must never sit on the redirect path; it is fire-and-forget to Kafka.

plaintext
Client → LB → API servers
              ├─ shorten: ID gen → base62 → write MySQL → warm Redis
              └─ redirect: Redis hit? → 301 : MySQL → populate cache → 301
              Kafka ← async workers → ClickHouse (analytics)

More practice in this topic

One dispatch a week

The trace behind each problem, the tradeoff that explains it, and one technical dispatch per week — no noise.

One technical dispatch per week. No noise.