Read-Heavy Systems: URL Shortener, ID Generator, Key-Value Store
Hook #
This course is the payoff of the whole System Design quarter: taking the method (Course 10.1) and the building blocks (Course 10.2) and composing them into complete, end-to-end designs. And the most important thing to understand before you start is that these classic problems are not 14 architectures to memorize — they're a handful of recurring patterns wearing different costumes. "Design a URL shortener" looks like a specific product, but it's really a thinly disguised question about hashing, storage, and a read-heavy access pattern. "Design a unique ID generator" is about generating unique values across many machines without coordination. "Design a key-value store" is replication and partitioning applied. This first lesson groups the read-heavy systems — URL shortener, ID generator, KV store — precisely to make the pattern visible: systems where reads vastly outnumber writes, so the whole design bends toward serving reads fast, cheap, and at scale. Learn the pattern once, and you can design any of dozens of read-heavy systems.
What you'll be able to do by the end of this lesson #
- Design a URL shortener end to end: the short-code generation (hashing vs. counter+encoding), the read-heavy redirect path (cache-first), and the storage.
- Explain distributed unique-ID generation approaches (UUID, database auto-increment, Snowflake-style timestamp+machine+sequence) and their trade-offs (sortability, coordination, size).
- Explain the read-heavy design pattern: reads ≫ writes, so optimize the read path with caching and replication, and accept that the write path can be simpler.
- Extract the transferable pattern from all three: identify the access pattern first, then let it drive the architecture.
A quick try before we start #
Before reading: a URL shortener gets maybe 100 new links per second but 100,000 redirects per second — a 1,000:1 read-to-write ratio. Given that imbalance, where should almost all your design effort go? (The read path — the redirect. Redirects must be fast and cheap at massive scale, so you cache aggressively, replicate reads, and keep the lookup a simple key→value. The write path, creating links, is comparatively trivial.) That instinct — let the read/write ratio dictate where the design effort goes — is the core of every read-heavy system, and recognizing the ratio first is the move.
Why this matters here #
Read-heavy systems are the single most common shape in production — the vast majority of real applications read far more than they write (social feeds, product catalogs, content sites, most APIs) — so the read-heavy pattern is the one you'll apply most often. Designing for it well means the difference between a system that scales cheaply and one that buckles: caching hot data, replicating for read throughput, and keeping the read path simple are what let a read-heavy system serve enormous traffic on modest infrastructure. And the specific techniques here recur everywhere: short-code generation is hashing and base-62 encoding (used for any compact unique identifier); distributed ID generation is a problem every multi-machine system faces (you can't rely on a single database's auto-increment when you have many databases); and the KV-store design is the foundation under caches, session stores, and NoSQL databases. Learning to recognize "this is a read-heavy system" and reach for the read-heavy playbook is one of the highest-frequency design skills you'll use.
Within the course, this is the first case-study family, and it demonstrates the whole point of the course: composition of the fundamentals into designs. The URL shortener composes hashing (the data-structures courses), caching and read replicas (Course 10.2, and the databases/distributed-systems courses), and estimation (Course 10.1's back-of-envelope). Distributed ID generation applies the coordination and consistency ideas from Quarter 9 (generating unique IDs across machines is a mini distributed-systems problem — do you coordinate, or design so you don't have to?). The KV store is replication and partitioning (Quarter 9) made into a product. Grouping these three as "read-heavy systems" makes the transferable pattern explicit — which is exactly how you should hold system design: not as memorized architectures, but as a small set of patterns (read-heavy, feed, real-time, storage, transactional — the five families of this course) that you recognize and apply.
The engineer's lens #
The first insight is that the access pattern — especially the read/write ratio — is the single most important thing to establish, because it determines where the entire design effort goes; recognizing "this is read-heavy" instantly gives you the playbook. A read-heavy system (reads ≫ writes) bends its whole architecture toward the read path: cache aggressively (most reads hit the cache, never the database), replicate for read throughput (many read replicas, one primary for the rare writes), and keep the read a simple, fast lookup (often a key→value, which is why a URL shortener's core is essentially a hash map at scale). The write path can be comparatively simple because writes are rare. This is a pattern you apply the moment you recognize the ratio — and the recognition is the skill. It generalizes far beyond these three systems: a product catalog, a content site, a social profile, most read APIs are all read-heavy, and the same playbook (cache + replicas + simple read path) serves them all. The mirror image — write-heavy systems (logging, metrics, event ingestion) — flips the playbook toward the write path (LSM-tree storage, sharding, async processing), which is why establishing the ratio first matters so much: it tells you which of two very different playbooks to reach for. When you start any design by asking "what's the read/write ratio?", you're doing the single highest-leverage thing in system design, because the answer routes you to the right pattern.
The second lens is distributed unique-ID generation as a small, sharp lesson in "design so you don't need coordination" — a recurring theme where the best answer avoids the hard distributed-systems problem rather than solving it. Generating unique IDs is trivial on one machine (a database auto-increment column). Across many machines it becomes a genuine distributed-systems problem: if every machine must coordinate to agree on the next ID, you've introduced a consensus bottleneck (slow, a single point of contention). The elegant solutions avoid coordination: UUIDs are random enough to be unique without any coordination (but large and unsortable); Snowflake-style IDs compose a timestamp + a machine ID + a per-machine sequence number, so each machine generates unique, roughly-time-sortable IDs independently with no coordination (the machine ID guarantees no two machines collide, the sequence handles same-millisecond IDs on one machine). The insight — and it's a deep one — is that the best distributed designs often sidestep coordination rather than paying its cost: instead of "how do we coordinate to agree on unique IDs?", you ask "how do we design so each node can generate unique IDs without coordinating?", and the answer (partition the ID space by machine) is far cheaper. This "avoid the need for coordination" instinct is one of the most valuable in distributed system design — it's the same reason CRDTs (Quarter 9) design conflicts out of existence rather than resolving them, and the same reason consistent hashing lets nodes join without a coordinator. Recognizing that the elegant answer to a distributed problem is often "restructure so the hard part disappears" — not "solve the hard part" — is a mark of design maturity, and the humble ID generator teaches it cleanly.
What to focus on in the resources #
- The three worked designs (Alex Xu), read for the pattern. Work the URL shortener, ID generator, and KV store through the method (requirements → estimate → design → trade-offs). The goal isn't to memorize each — it's to see the read-heavy pattern recurring across all three, and to internalize the method that produces them.
- The read-heavy playbook. Cache-first read path, read replicas, simple key→value lookups. Establish the read/write ratio first, then apply. This is the transferable takeaway.
- Distributed ID generation and coordination-avoidance. Understand UUID vs. Snowflake and why Snowflake avoids coordination (timestamp + machine ID + sequence). Absorb the broader lesson: design so you don't need coordination.
- Skip on first pass: exhaustive short-code-collision handling, every ID-scheme variant, and deep KV-store internals (you have the replication/partitioning foundations from Quarter 9). Get the read-heavy pattern, coordination-avoidance, and the method applied.
Explain it back #
Explain to a colleague why "design a URL shortener" is really a read-heavy-systems problem, and how the read/write ratio shapes the design. A strong answer: a URL shortener does far more redirects (reads) than link creations (writes) — often 1,000:1 — so nearly all the design effort goes to the read path: cache the code→URL mapping aggressively (most redirects hit the cache), use read replicas for throughput, and keep the lookup a simple key→value; the write path (creating links) is comparatively trivial. The key move is establishing the read/write ratio first, because it routes you to the read-heavy playbook (vs. the very different write-heavy one). Bonus: explain how distributed unique-ID generation (Snowflake: timestamp + machine ID + sequence) avoids coordination rather than solving it — and why avoiding coordination is often the elegant answer.
Where this connects #
Backward: The hashing course (short codes and KV lookups) and Course 10.1's estimation (the read/write ratio comes from back-of-envelope numbers) and 10.2's caching and consistent hashing. The KV store is Quarter 9's replication/partitioning; coordination-avoidance echoes CRDTs and consistent hashing from Quarter 9. This composes the fundamentals into designs — the course's whole thesis.
Forward: Lesson 2 covers feed and timeline systems (the fan-out pattern), lesson 3 real-time systems, lesson 4 large-scale storage, lesson 5 transactional/spatial systems — the five design-pattern families. Each is a family of case studies teaching a transferable pattern, and together they're the composition practice that the URL-shortener capstone (from Course 10.1) and the write-up-collection project draw on.
That's the free preview. Sign in to continue this course.
Sign in to continueNew here? Make a desk →