SD System Design In Depth
0%
design system-designanalyticsreactionsdesign

Design: live reactions at high throughput

Module 4.3: Probabilistic Sketches & Stream Analytics Updated Sep 18, 2026
📄 Cheat Sheet
Streaming a Million Likes/Second: Real-Time Interactions on Live Video
InfoQ Streaming a Million Likes/Second: Real-Time Interactions on Live Video Watch on YouTube ↗

LinkedIn engineer Akhilesh Gupta explains the real production design for live-video likes: persistent connections, subscription-based fan-out and multi-data-center dispatch.

0:00 / --:--

System Design: Live Stream Reactions

During live events (Apple keynotes, Twitch streams), users can send reactions (hearts, claps) that float across everyone's screen. The challenge is ingesting tens of thousands of clicks per second and broadcasting them with sub-second latency.

Ingestion and Local Buffering

If millions of users click "heart", we cannot send every click to the database. The client app throttles clicks, sending a batch (e.g., "5 hearts") every second. The API gateway receives these and routes them to an ingestion service. The ingestion service buffers these counts in memory for 1-2 seconds, aggregating the total counts per reaction type.

Pub/Sub Broadcast

The aggregated counts (e.g., "Stream123: +500 hearts, +200 claps") are published to a Redis Pub/Sub topic. The WebSocket servers handling the viewer connections subscribe to this topic. When they receive the aggregated update, they push it down to the clients. The client-side JavaScript then renders the floating animations based on these aggregated numbers, creating the illusion of continuous individual clicks.

Decoupled Analytics

Do not make volatile buffers the only accepted record if permanent counts matter. Persist an event or idempotent delta before acknowledging it, then derive coarse broadcast updates separately. If Redis Pub/Sub drops an update or a WebSocket server restarts, clients should refetch a versioned snapshot and resume from a sequence boundary. Batching lowers fanout bandwidth, but it sacrifices one-to-one animation fidelity and adds up to one batch interval of delay; bound per-client queues and drop visual updates rather than exhausting memory for a slow viewer.

Worked example: why aggregation is mandatory

A live event has 2 million concurrent viewers; 5 percent react each second.

DesignMessages delivered per second
Forward every reaction to every viewer100,000 reactions x 2,000,000 viewers = 200 billion, impossible
Aggregate per stream every 500 ms, send one summary to each viewer2 updates x 2,000,000 viewers = 4 million
Spread over 200 edge servers at 10,000 connections each20,000 messages per second per server, very manageable

On the ingest side, clients batch taps locally (for example, send "5 hearts" once per second), so 100,000 reactions per second become at most one request per active user per second, and ingest nodes sum them per stream before publishing.

Fan-out design

ApproachHow it routesTrade-off
Broadcast to all edge serversEvery server receives every stream's updatesSimple; wasteful with thousands of concurrent streams
Subscription registryEdge servers register "I have viewers of stream S"; dispatcher sends only thereEfficient; registry must handle churn as viewers join and leave
Pub/sub channel per stream, such as Redis Pub/Sub or a Kafka partitionEdge servers subscribe to channels for their streamsLeverages existing infrastructure; hot channels need sharding

LinkedIn's talk describes the subscription approach: frontend nodes hold persistent connections and track which live videos their clients watch, and a dispatcher layer forwards each like only to frontend nodes with subscribers for that video, including across data centers.

Durability vs display

If the reaction total is a permanent metric, write an idempotent delta (stream ID, ingest node, batch sequence) to a durable log before acknowledging, and derive the displayed counter from that log. The animation path can be lossy: if a pub/sub message is dropped or an edge server restarts, clients simply fetch the current total and continue. Protocol choice: server-sent events suit one-way push of summaries; WebSockets suit apps that also send reactions and comments over the same connection.

Check yourself Question 1 of 3
Slow viewers recall
From: System Design: Live Stream Reactions

A WebSocket server notices that one viewer on a poor connection is falling behind on reaction updates. What should it do?

Key Takeaways

Client-side throttling and batching is the first line of defense against high throughput.
Server-side memory buffering aggregates raw events into periodic updates.
Visualizing high-volume data relies on client-side rendering interpolation, not 1-to-1 event mapping.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue