System 12.1 — URL Shortener
In one line
The perfect first HLD: small data, global scale, one hot read path (redirect) and one rare write path (create).
Think of it like this
Bit.ly. You paste a long, ugly link and get back a tiny one like 'sd.ly/x7K2'. Behind the scenes it's really just a giant lookup table: short code in, long URL out.
Key ideas
- 01
Scale: ~100M URLs/day → ~1.2k writes/s, ~11k reads/s (avg), peak 5–10x.
- 02
API: POST /api/shorten {url} → {shortId}; GET /{shortId} → 301/302 redirect (or JS). 301 = permanent, cached; 302 for analytics-aware redirects.
- 03
Encoding: counter → Base62 (0-9a-zA-Z) gives 62^7 ≈ 3.5T ids in 7 chars — no md5 collisions to fight.
- 04
Storage: RDBMS with (shortCode) unique PK; the write path is rare, reads are by key → index lookups trivial.
- 05
Cache: hot codes in Redis (cache-aside) — redirect p99 goes from 5ms to ~2ms, DB relieved.
- 06
Flow: POST → lock+counter (or ZK/Redis INCR) → generate code → insert → respond 201. GET → check cache → miss → lookup DB → redirect 301 + count event.
- 07
Failures: cache DOWN → still works (falls to DB); DB writers locked per counter — make counter a Redis INCR to de-throttle.
- 08
Extras: custom alias, expiry TTL, analytics events (async → Kafka), and remember 301 gets cached by browsers → analytics need 302 or client-side pixel.
Java / Spring map
- →
Spring Boot: @RestController + repository; Redis for cache + INCR counter; events published on redirect.
Code & diagrams
The only 'algorithm' the whole problem needs.
public final class Base62 {
private static final String ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static String encode(long n) { // 0 → "0", 12345 → "3d7"
StringBuilder sb = new StringBuilder();
do { sb.append(ALPHABET.charAt((int) (n % 62))); n /= 62; } while (n > 0);
return sb.reverse().toString();
}
public static long decode(String s) {
long n = 0;
for (char c : s.toCharArray()) n = n * 62 + ALPHABET.indexOf(c);
return n;
}
}
// Counter 1,250,000,000 → "1fEC7Ya" — 7 chars for ~1.2 billion urls.Explain without notes
Why 301 breaks analytics + how a 302-and-pixel (or JS redirect) keeps counting.
Practice
Work the scale: 100M/day, 5-year retention → codes, DB size, cache size, QPS at peak.
Trade-offs
- ↔
Counter-based ids are guessable (SEO/hijack risk); random ids cost collision handling. Trade guessability vs complexity.
Run it in production
You've designed it. Now build, operate, and break the same idea hands-on in the DevOps courses:
Completion checklist
I can present shortener across all 13 template sections in 25 minutes.