MediumProblem 17 of 36 in the system design series
Design Facebook Live Comments: Real-Time Fan-Out to Millions

Live comments are the scrolling conversation beside a live video. Someone types a reaction to a goal or a product reveal, and within a moment it shows up for everyone else tuned in. This article designs a Facebook Live-like comment system as an interview exercise; it does not describe how any real company has built theirs.
The problem is a favourite because it isolates one idea very cleanly: the gap between how much data is written and how much must be delivered. Each comment is tiny and written once, yet a popular broadcast may need to hand that same comment to a million open connections. Candidates who treat it as a simple database problem miss the point entirely.
The tough parts are real-time push, fan-out across a fleet of servers, and surviving the occasional broadcast that draws an enormous audience. Along the way the design has to choose a transport, decide how servers learn about new comments, and decide what to do when comments arrive faster than anyone could read them.
This is an interview practice design for a Facebook Live Comments-like service, built from first principles. It is not a description of how Facebook Live Comments is actually built.
Functional Requirements
The feature set is intentionally narrow. Anyone watching a broadcast can type a comment on it. Everyone watching that video sees new comments show up within seconds, with no page refresh. And a viewer who tunes in partway through can scroll back to read what was said earlier, page by page.
Those three requirements map onto three distinct paths: a write path for posting, a push path for live delivery, and a read path for history. Treating them separately is what allows each to scale in its own way. Threaded replies, emoji reactions and moderation are valuable features, but each adds its own complexity and none of them changes the core delivery problem, so they are parked for this discussion.
Post a comment
A viewer writes a comment on a live video.
POST comment
See comments live
New comments appear for every viewer, without refreshing.
pushed to viewers
Load earlier comments
Joined late? Scroll up to see what was said before.
paginated history
- Out of scope today: replies, reactions and content moderation
Non-Functional Requirements
Latency is what makes the feature feel live. If a comment takes more than about two seconds to reach other viewers, people end up reacting to moments that have already passed and the conversation stops making sense. Fan-out is the second pressure: a single major broadcast, such as a cricket final, may have millions of concurrent viewers all waiting on the same stream of comments.
Availability outranks strict consistency here. A viewer seeing a comment a moment late, or occasionally not at all, is a minor blemish; the comment panel going dark during a big event is a headline. That choice gives us permission to use best-effort delivery on the live path. Finally, the system must run hundreds of thousands of broadcasts concurrently, so every component needs to scale out horizontally.
Low latency
A comment reaches viewers within about two seconds.
< 2 s end-to-end
Massive fan-out
One hot stream can have millions of viewers.
millions / video
Availability first
A late or missing comment is fine; going down is not.
eventual consistency
Many streams at once
Hundreds of thousands of live videos at the same time.
horizontal scale
Scale Estimation
Assume about 1 billion comments per day across every live video, which averages roughly 12,000 writes per second. Any reasonably sized distributed database absorbs that without strain. At about 500 bytes per comment, storage grows around 500 GB a day, again comfortable.
The worrying figure is fan-out. Take one broadcast with 1 million viewers receiving 100 comments per second: that is 100 million individual deliveries per second for a single video. So the estimate clearly says the write side is routine and nearly all design attention belongs on delivery. Every later decision, from transport to routing to batching, aims at shrinking or distributing that multiplication.
1billion
Comments per day
12K avg
Comments per second
writes are easy
500GB / day
Storage (500 B each)
100M / s
Hot stream fan-out
1M viewers × 100 comments/s
Writing comments is easy → delivering them to viewers is the real problem
Core Entities & API
The data model stays small: a live broadcast, the comments attached to it, and the people who author or follow them. Posting uses POST /videos/{id}/comments with the text and returns a comment ID plus timestamp, which the client can use to show its own comment immediately.
History is fetched with GET /videos/{id}/comments?before= using a cursor, returning a page of older comments and the next cursor. Cursors work better than offsets here because new comments are constantly arriving, which would shift offset-based pages. Live delivery uses GET /videos/{id}/comments/stream, a long-lived SSE connection on which the server keeps sending each new comment as it lands.
Core entities
Live videoCommentViewer
API
- POST /videos/{id}/comments { text }→ { comment_id, created_at }
- GET /videos/{id}/comments?before=→ { comments[], next_cursor }
- GET /videos/{id}/comments/stream→ SSE stream of new comments
High-Level Design
A posted comment travels through a load balancer to a comment service that validates it and persists it to a comments database such as Cassandra. The partition key is the video ID and rows sort by time, so loading the latest page for a late joiner is a single partition read.
After storing the comment, the service publishes it to a pub/sub channel dedicated to that video, for example on Redis pub/sub. Crucially, the comment service has no idea who is watching. It writes once and announces once, keeping the posting path fast and independent of audience size.
Realtime servers hold the open viewer connections. Each one listens only on channels for videos its connected viewers are watching. When a comment arrives on a channel, the server writes it to every local connection for that video, so a single publish can reach thousands of people on one machine. Storage happens once on the write side, and multiplication happens only at the edge where it is unavoidable.
Write path: store once · Read path: fan out through pub/sub
Deep Dive 1 — Real-time Delivery
Polling every few seconds is easy to build and works through any network, but with millions of viewers it produces a torrent of mostly empty requests and still feels sluggish. WebSockets give a persistent, bidirectional, low-latency pipe, yet this feature mostly needs data moving in one direction, and WebSocket upgrades require extra attention at proxies and load balancers.
Server-sent events fit the shape of the traffic best. The server streams comments over an ordinary long-lived HTTP response, and browsers handle reconnection automatically. Since a viewer posts far less often than they read, posting remains a regular POST routed through the normal load balancer, while SSE carries only inbound comments.
Reconnection is handled gracefully through Last-Event-ID. When a connection drops and the browser reconnects, it sends the ID of the last comment it saw, and the server can replay anything newer from storage so the viewer does not end up with a gap.
Polling
- + Simple
- + Works everywhere
- − Millions of empty requests
- − Laggy
WebSockets
- + Two-way, very low latency
- − We mostly need one way
- − More work at proxies
Server-sent eventsChosen
- + Server push over HTTP
- + Auto-reconnect built in
- − Server → client only
- Posting is rare → keep it a normal POST; SSE only for receiving
- Reconnect with Last-Event-ID → server replays what was missed
Deep Dive 2 — Fan-out with Pub/Sub
The core question is how one comment reaches viewers scattered across hundreds of realtime servers. The flow begins with a viewer whose SSE connection is assigned to one particular realtime server. That server joins the channel named after the video, such as video:{id}, exactly once, regardless of whether one or ten thousand of its viewers are watching that broadcast.
When a comment is posted, the comment service publishes it to that single channel and moves on. Each listening server receives one copy and loops over its own local connections to deliver it. This two-level fan-out keeps the broker's work proportional to servers, not viewers.
Routing makes it more efficient still. The load balancer uses consistent hashing on the video ID, so viewers of the same broadcast cluster onto a small group of servers. Fewer servers then listen on each channel, and every message is useful to many local viewers. The pub/sub cluster is also sharded by video ID, so no single broker has to carry every broadcast.
- 1Viewer connectsOpens an SSE stream to a realtime server
- 2Server subscribesJoins channel video:{id} once, for all its viewers
- 3Comment publishedComment service publishes to that one channel
- 4Local fan-outEach subscribed server pushes to its own viewers
- 5Route by video IDSame video's viewers land on the same few servers
- Pub/sub cluster sharded by video ID → no single broker carries every stream
Deep Dive 3 — Hot Streams
A stream with ten million viewers needs extra tactics. Batching is the first: rather than emitting one message per comment, each realtime server collects comments for a few hundred milliseconds and sends them as one bundle. Viewers notice no difference, but message count and per-message overhead drop sharply.
Sampling is the second. Nobody can read a thousand comments a second, so for very large broadcasts the server sends a ranked subset, favouring friends, highly liked comments and verified accounts. A relay tier adds structure to fan-out: the broker hands every comment to a handful of regional relays, which pass it along to edge servers in their region, so a comment crosses each long-distance link only once. Finally, per-user rate limits and spam filtering protect the write path from floods during big moments.
Batch comments
Send one message every few hundred milliseconds, instead of one per comment.
Sample when it's too fast
Nobody reads 1,000 comments a second — show a ranked sample: friends, top, verified.
Relay tier for fan-out
Pub/sub → regional relays → edge servers; each comment crosses regions once.
Rate-limit the writers
Per-user limits and spam filters keep the write path healthy.
Trade-offs
SSE keeps one-directional push simple, while WebSockets earn their extra complexity only when the product genuinely needs two-way messaging such as full chat. Redis pub/sub is lightweight and quick but fire-and-forget, so a disconnected listener simply misses messages; Kafka offers durability and replay at the cost of more weight and latency.
Sampling cuts load and visual noise dramatically, but it means not every viewer sees every comment, which is a product decision as much as a technical one. The guiding principle is best-effort live delivery backed by durable history. A missed push is tolerable because the database remains the source of truth and fills gaps on reconnect or scroll. In short: persist each comment once, fan out per video, and batch and sample when a broadcast gets huge.
SSE vs WebSockets
SSE is simpler for one-way push; WebSockets suit true two-way chat.
Redis pub/sub vs Kafka
Redis is light and fast but fire-and-forget; Kafka is durable but heavier.
Sampling
Much less load and noise — but not every viewer sees every comment.
Best-effort live, durable history
A missed live push is fine; the database stays the source of truth.
Store once. Fan out by video. Batch and sample hot streams.
Key takeaways
- Writes are easy (about 12K per second); delivering 100M messages per second to one hot stream is the challenge.
- Store each comment once in a database keyed by video, then publish it to a per-video channel.
- Push with SSE; keep posting as a normal POST and use Last-Event-ID to recover missed comments.
- Route viewers by video ID so few servers listen on each channel and fan-out stays local.
- For huge streams, batch messages, show a ranked sample, add regional relays and rate-limit writers.
Interview questions
How do live comments work on a streaming video platform?
A comment is posted to a comment service, stored in a database partitioned by video, and published to a pub/sub channel for that video. Realtime servers holding viewer connections join the channels their viewers need and push each new comment over server-sent events. Late joiners load older comments from the database using cursor pagination.
Should live comments use SSE or WebSockets?
Server-sent events are usually the better fit because comments mostly flow from server to viewer. SSE works over plain HTTP, reconnects automatically and supports resuming with Last-Event-ID. Posting a comment can remain a normal POST request. WebSockets are worth it when the product needs frequent two-way messages, such as a full chat room, and the team can manage the proxy and load balancer considerations.
How does a comment reach viewers connected to different servers?
Each realtime server joins a pub/sub channel once per video its viewers are watching. The comment service publishes each new comment to that channel, every listening server receives one copy, and each server pushes it to its own local viewers. Routing viewers by video ID with consistent hashing keeps the number of servers per channel small.
How do you handle a live stream with millions of viewers commenting?
Combine several techniques. Batch comments on each server every few hundred milliseconds instead of sending them one by one. Show a ranked sample, since no one can read a thousand comments per second. Add a regional relay tier so each comment crosses regions once. Rate-limit and spam-filter writers so the posting path stays healthy during the spike.
What database should store live video comments?
A wide-column store such as Cassandra works well, with the video ID as partition key and comments sorted by time. That layout makes writing fast and makes fetching the most recent page, or paging backward with a cursor, a single-partition read. At roughly 12,000 writes per second and about 500 GB per day, write volume is modest for such a database.
Keep practising
- Learn the building blocks in the free system design course.
- Rehearse answers with system design interview questions.
- See which open jobs fit your skills: upload your resume.