Layered Architecture
Traditional n-tier architecture pattern
A microblogging platform at Twitter/X scale — tweet ingestion, hybrid fan-out timelines, typeahead search, and real-time notifications, each broken into its own diagram.
Denser dots = higher throughput. Hover any edge for its full contract.
Rough, order-of-magnitude numbers. The point is to justify the architecture, not to be exact.
No system is born with queues and caches. Every box was added because something was about to break. Play a stage and the diagram above shrinks to what existed at that point in the story.
The simplest version of the system: a client submits a tweet through an API gateway to a Tweet Service, which mints a globally unique ID via a Snowflake-style generator, persists the tweet in Cassandra, and issues pre-signed URLs so media uploads bypass the API tier entirely.
There are no timelines, no search, no notifications — just the core write path. Every tweet is written synchronously, and users read by scanning the database directly. This works for a few thousand users but collapses under millions.
Scale pressure: With millions of users, scanning every tweet to find those from followed accounts is thousands of times too slow — we need precomputed feeds
A Kafka event bus decouples the write path from the read path. After persisting a tweet, the Tweet Service publishes a tweet_created event. A Fan-out Dispatcher reads the author's follower count from the Social Graph Store and decides between push (most users) and pull (celebrities with 50M+ followers).
The Fan-out Worker continuously drains the stream and pushes tweet IDs onto every follower's precomputed timeline in both the durable Cassandra store and the Redis cache. The Timeline Service now assembles feeds by reading precomputed ID lists from Redis, hydrating full tweet content from the Tweet Store, and merging in celebrity tweets from a dedicated pull cache — all in well under a second.
Scale pressure: With engagement growing, users need real-time alerts when their content is liked or mentioned, and the platform must surface what is trending right now
Engagement events — likes, retweets, replies, mentions — flow through a shared Kafka topic decoupled from the action that caused them. A Notification Worker consumes each event, builds a per-recipient payload, appends it to a DynamoDB Notification Store sharded by user ID, and forwards eligible events to the Push Gateway (APNs/FCM) for immediate mobile delivery.
Independently, the Trending Aggregator maintains a sliding-window count of hashtag and topic mentions from the same engagement stream, refreshing a Redis cache with the top-N topics per region. The Notification & Trends Service serves both feeds as a read-only API — it never computes anything itself.
Scale pressure: At hundreds of millions of users, users expect instant, ranked suggestions with every keystroke and full-text search across tweets and accounts — browsing timelines is no longer enough
A Typeahead Service serves prefix suggestions by checking Redis first (hot prefix cache), then falling back to a sharded cluster of in-memory ranked tries where every node stores its top-K completions pre-sorted by popularity — a keystroke is a lookup, not a computation.
Offline, a Query Log in Kafka feeds an Aggregation Job that tallies query frequencies. The Trie Builder periodically reads fresh frequencies and atomically swaps a newly built trie onto the serving shards, so the hot read path never pays a rebuild cost. Separately, the Search Service handles full-text queries over the Elasticsearch index for submitted searches — a heavier path than typeahead's per-keystroke lookups.
This is the finished architecture: four semi-independent sub-systems — write path, timeline, notifications, search — each decoupled by Kafka, each scaling on its own signal.
A diagram shows what exists; a trace shows what happens. Press play on a flow, or click any step, and the diagram above lights up the exact path that request takes.
The write path — from compose to a durable, event-published tweet. Scoped entirely to frame 1.
The read path — how a user's feed is assembled with sub-second latency. Scoped entirely to frame 2.
How a keystroke becomes an instant, ranked suggestion. Scoped entirely to frame 3.
The offline pipeline that keeps typeahead rankings fresh without ever blocking a live query. Scoped entirely to frame 3.
From an engagement action to a push notification and a readable feed. Scoped entirely to frame 4.
Every box on the canvas, and the job it does. Click a card to locate it in the diagram; click the node itself for the full deep dive.
Handles the moment a tweet is created: validating content, minting a globally unique ID, persisting the tweet, and kicking off everything that has to happen next.
Serves the personalized feed a user sees on open, in well under a second.
Turns every keystroke in the search box into an instant, ranked suggestion, and serves full-text search over tweets and accounts.
Fans engagement events (likes, retweets, replies, mentions) out to the people who need to see them, and surfaces what's trending right now.
An architecture is a record of trade-offs. For every major choice here: what won, what lost, and why the constraints made it so.
At ~6,000 writes/sec sustained (and much higher during spikes), a single auto-increment counter becomes a contention point, and per-shard counters can collide across shards. A Snowflake-style generator produces IDs from a timestamp, worker ID, and sequence number, giving global uniqueness and rough time-ordering with zero coordination between nodes.
An account with 50M+ followers would require 50M+ timeline writes per tweet under pure push — the estimates make that write explosion untenable. Pure pull would make every timeline read for every user pay a fan-in join, which is too slow at ~1000:1 read-to-write ratio. The hybrid splits the difference: most users get a precomputed, instant feed, while the rare high-follower accounts are merged in at read time.
At a peak of 500K suggest requests/sec, ranking candidates on every keystroke is not viable. Precomputing each prefix's top-K completions ahead of time turns every request into a lookup instead of a computation — the core insight behind both referenced typeahead designs.
In-place updates to a structure being read 500K times a second would require locking that the hot path can't afford. Rebuilding fresh and swapping atomically keeps every live read lock-free; a small real-time overlay covers the gap for suddenly trending terms without paying for a full rebuild.
Notification reads are always single-item lookups by user ID — exactly DynamoDB's partition-key access pattern. This gives predictable latency even during a viral-tweet spike that floods the write path with mentions and likes for one popular thread.
Follower lookups sit on the hot path for every fan-out decision and every timeline push, at a completely different volume and access pattern than tweet writes. Isolating the graph store lets it be sharded and scaled by adjacency-lookup load rather than being coupled to tweet throughput.
Reading a system means sensing where it cracks under 10× load. These are the pressure points of this design, and how it holds.
A tweet from an account with 50M+ followers would need 50M+ timeline writes within seconds if fanned out naively, overwhelming the Timeline Store and the Fan-out Worker.
The Fan-out Dispatcher routes celebrity tweets away from push fan-out entirely. Their tweets are fetched on demand from the Celebrity Tweet Cache and merged into each requester's timeline at read time instead.
A small number of popular prefixes receive a hugely disproportionate share of the 500K/s suggest traffic, which can overload whichever single trie shard happens to own them.
Skew-aware prefix sharding splits busy prefixes across more shards than rare ones, and the Suggestion Cache absorbs a large fraction of repeat hits before they ever reach a shard.
With only a periodic offline rebuild (minutes to hours), a breaking-news term can spike in seconds and stay invisible in suggestions until the next rebuild cycle.
A lightweight real-time overlay is blended into typeahead results at query time, and the separate Trending Aggregator keeps its own short sliding window in Redis independent of the trie rebuild cadence.
A single viral tweet can generate millions of mention, like, and reply events within minutes, all needing to fan out through the Notification Worker and Push Gateway simultaneously.
Kafka buffers the engagement event burst so the Notification Worker drains it at a sustainable rate rather than being hit synchronously, and notification writes are batched per recipient shard.
A user who hasn't opened the app in a while has no warm entry in the Timeline Cache; if many dormant users return around the same event, that's a burst of cold reads hitting the Timeline Store at once.
The durable Timeline Store in Cassandra is sized for this fallback path, and cache repopulation happens lazily on read rather than requiring a full timeline recomputation.
Most of this architecture exists because any one box can die. Take a component offline and the diagram above shows the blast radius: what goes down, what degrades, and what the user feels.
Tweeting fails — users cannot post new content. But timelines, search, and notifications keep working from cached data.
New tweets cannot be persisted — tweeting fails. Existing tweets remain readable from the cache and CDN. Timeline hydration for old tweets is lost.
Tweeting itself still works — the Tweet Service writes to Cassandra first. But timelines freeze, search indexing stops, and notifications halt until Kafka recovers.
Users notice nothing immediately — tweets still persist. But the fan-out pipeline stalls: non-celebrity tweets never reach followers' timelines until the dispatcher recovers.
Timeline reads for users not in the Redis cache fail — cold starts, dormant users returning, and cache evictions all turn into errors. Already cached feeds keep working.
Timeline reads slow down dramatically but don't break — every request now falls through to the durable Timeline Store (Cassandra). Page load times jump from ~3ms to ~15ms.
Typeahead suggestions stop working entirely — users see no autocomplete dropdown. Full-text search (an independent service) is unaffected.
Typeahead degrades noticeably — the Redis cache still serves hot prefixes from its 5-minute TTL, but any miss that would fall through to the trie fails. After the cache drains, all suggestions disappear.
Notifications stop arriving entirely — no in-app feed updates and no push notifications. The engagement actions (likes, retweets) themselves succeed without issue.
The notification feed in the app goes blank — users see no historical notifications. Push notifications that were already delivered remain on the device, and new likes/retweets still complete.
If you can answer these without scrolling back up, the architecture is yours. Try each one out loud before revealing.
Every great system starts as a sketch on a whiteboard. The ability to zoom out and see the whole picture (how services connect, where data flows, what breaks and why) is what separates engineers who build features from engineers who build systems. This diagram is more than boxes and arrows. It's a map of decisions, trade-offs, and intentional design.
Studying architectures isn't just about passing interviews. It's about training your intuition. The more systems you take apart, the better you get at sensing where a monolith will crack, where a queue belongs, or when a cache is hiding a deeper problem. You start seeing patterns instead of chaos.
So keep reading, keep tracing those edges, keep asking "why this way and not that way." The engineers who truly understand large systems are the ones who never stop being curious about how things fit together. That curiosity is the only ingredient that really matters.
Atharva Arbat@arbat_atharva
Traditional n-tier architecture pattern
A server-side rate limiting system that protects APIs from abuse using sliding window counters and Redis-backed distributed state.
A ranked prefix-completion system that returns the top-K suggestions within the keystroke latency budget using an in-memory precomputed trie and an offline popularity build pipeline.