Skip to main content
News Feed / Timelinelesson 3 of 4 · 3 min read

The Serving Architecture

Identifiers, never bodies

Make one load-bearing decision about your feed cache: it holds post identifiers, never post bodies.

Keep each person's feed as a sorted set of maybe 800 identifiers scored by time. Entries are 8 bytes instead of kilobytes, an edited or deleted post is never stale across a thousand copies, and your fan-out writes stay tiny.

Pay for it with a second step at read time, called hydration. Take the top 50 identifiers, fetch those posts from a post cache, batch the misses, and assemble the response. Two cache round trips, both batched, comfortably inside your budget.

Follow the write path all the way through. Dana's post lands in the post service, which saves it and emits an event. Fan-out consumers read that event, look up her followers, filter to the ones eligible for pushing, and insert the identifier into each of their sorted sets, trimming each to its cap.

Value the queue between posting and fan-out, because it absorbs your bursts. A viral moment makes feeds seconds stale instead of making posting slow, and that is the right way round.

The memory arithmetic

Do the memory arithmetic to keep everybody honest. A hundred million people times 800 entries times roughly 20 bytes with overhead is about 1.6 terabytes of feed cache, a real but ordinary cluster sharded by user.

Shrink it by not materialising feeds for dormant people. If somebody has not opened the app in 30 days, drop their cache entirely.

Rebuild on their return. A feed builder reconstructs the sorted set from their follow list on demand, they take one slow load, and fan-out keeps it warm from then on.

See what you bought. Your active users get the fast path every single time, and the long tail of dormant accounts stops costing you terabytes.

the shape of it
ReaderFeed serviceFeed cacheIDs, sorted by timePost cacheID -> contentKafkapost eventsFan-out workersSocial graphfollower listsopen feedtop 50 IDshydrate batchnew postwho follows?insert ID
step 1 of 2
Reads take IDs from the feed cache and hydrate them from the post cache, while fan-out workers keep the ID sets fresh asynchronously.

Worked example

Ines inherits a feed system at a photo-sharing startup where the previous team cached each user's whole rendered feed as JSON, a text format for structured data, 300 KB apiece, in Memcached. Two problems surface within a quarter. Memory first: 20 million cached feeds at 300 KB is 6 TB, and the bill gets a meeting with the CFO. Then correctness: a user deletes an unflattering photo, and it keeps appearing in followers' cached feeds for hours, which becomes a support escalation and then a press question. Her rebuild stores only post IDs in Redis sorted sets, 16 KB per user instead of 300, cutting the cache to 320 GB. Deletes now work by deleting the post object itself; hydration finds a missing ID, drops it from the response, and lazily removes it from the set. Same hardware then serves 4x the users, and deleted photos vanish everywhere within seconds.