← All articles
NewsJuly 10, 2024

Real-time Data Streaming at Scale: Architecture Patterns

Handling 10k plus concurrent users with efficient data pipelines, WebSockets, SSE, and message queues.

By Kibet Brian

Real-time at scale is a fan-out problem. One event becomes ten thousand deliveries, so the architecture that matters is the one between your data source and the socket.

Push, do not poll

Polling multiplies load by client count regardless of change rate. Server-sent events cover one-way feeds with plain HTTP, WebSockets cover bidirectional traffic, and both beat polling by orders of magnitude.

feed.ts
export async function GET() {
const stream = new ReadableStream({
start(controller) {
const send = (event: string) =>
controller.enqueue('data: ' + event + '\n\n');
bus.subscribe('scores', send);
},
});
return new Response(stream, {
headers: { 'Content-Type': 'text/event-stream' },
});
}

Absorb bursts with queues

Spikes will exceed what your consumers handle. A message queue between ingestion and delivery smooths bursts, and per-channel batching turns ten thousand socket writes into far fewer.

Design for the burst, not the average. Averages never page you at 3am.

Pick the right transport

  • •Server-sent events for one-way feeds over plain HTTP with automatic reconnects.
  • •WebSockets for bidirectional traffic like chat, presence, and live collaboration.
  • •Short polling only as a fallback, and never as the primary strategy.

Scale out with pub and sub

One server cannot hold ten thousand sockets forever. Publish events to a shared bus and let every edge node subscribe, so any node can serve any client and capacity grows by adding identical nodes.

fanout.ts
bus.subscribe('scores', (event) => {
for (const socket of room.sockets(event.matchId)) {
if (socket.bufferedAmount < MAX_BUFFER) socket.send(event.payload);
}
});

Notice the backpressure check: a slow client must never block the room. Drop or coalesce for laggards, keep the fast path fast, and log who fell behind so capacity planning has data instead of guesses.

Share this article