SuryanandHome

News Feed / Timeline (e.g. Twitter-style)

Problem statement

Design a system where users follow others and see a chronological or ranked feed of posts at scale (fan-out on read vs write, mixed media).

How it works

Two classic strategies:

  1. Fan-out on write (push): when user posts, push post id into every follower’s feed cache (Redis list / sharded DB).
  2. Fan-out on read (pull): store posts by author; at read time, merge recent posts from all followees.

Analogy: Push = newspaper delivered to every doorstep nightly. Pull = you walk to each friend’s house and collect today’s notes when you open the app.

When to use push vs pull

ScenarioPrefer
Celebrity with 50M followersHybrid: push to normal users, pull merge for mega-followed accounts
Small follower countsPush for low read latency
Ephemeral storiesOften push + TTL

High-level design

Rendering diagram…

Components explained — this design

ComponentWhat it isWhy we use it here
Post serviceWrites new posts to durable store and emits events.Source of truth for content; publishing to Kafka enables fan-out workers without blocking the user’s POST response.
Kafka / KinesisDurable ordered log (see glossary).Buffers fan-out work; replays if workers lag; partition by author or post for ordering guarantees where needed.
Fan-out worker poolConsumers that push post ids into per-user feed lists.Implements push model feeds; horizontal scale by adding consumers (watch consumer lag).
Redis feed cacheLIST/ZSET of recent post ids per user.O(1) reads for home timeline first page; trim to cap memory.
Feed API + RankingAssembles hydrated posts; optional ML ranker.Read path composition; ranking should not block basic chronological fallback on outage.

Shared definitions: 00-glossary-common-services.md

Low-level design

Post storage

  • Cassandra / DynamoDB partition by user_id + time (wide rows) for write scalability.
  • Or PostgreSQL with partitioning if team strength is SQL.

Feed cache

  • Redis lists feed:{user_id} capped at N (e.g. 800) post ids — LPUSH + LTRIM.
  • TTL on inactive users to save memory.

Fan-out worker

  • Kafka consumers horizontally scaled; idempotent writes (dedupe by post_id).
  • Dead letter queue (SQS DLQ) for poison posts.

Ranking (optional)

  • Online: lightweight model in AWS SageMaker endpoint or TensorFlow Serving.
  • Offline: precompute scores batch to Feature Store.

Media

  • S3 + CloudFront for images/video; transcoding with Elastic Transcoder / MediaConvert.

E2E: post then read feed

Rendering diagram…

Tricky parts

ProblemSolution
Hot celebrityDon’t fan-out to millions; merge at read for those authors
Stale orderingHybrid timeline: merge push cache + pull recent from celebs
Global orderingTrue global order needs single writer or vector clocks — usually per-user relative order is enough
Muted / blocked usersFilter layer in Feed API reading social graph service

Caveats

  • Strong consistency between “posted” and “visible” is often relaxed; eventual fan-out acceptable with “sent” ack after durable log.
  • Compliance: geo-fencing content, GDPR delete must cascade to feed shards (async jobs).

Tech picks (example)

LayerAWSAzure
StreamKinesis / MSKEvent Hubs
CacheElastiCacheAzure Redis
CDNCloudFrontAzure CDN