SysDesignPrep.com
Interactive concepts

Routing messages across WebSocket gateways with broadcast, a connection registry or pub/sub: an interactive model

A chat service keeps each user’s WebSocket open on one of many gateway servers. When someone sends a message, the server handling it has to get it to whichever gateways hold the recipients’ connections. Broadcasting to every gateway is simplest and stops scaling almost at once. A connection registry or pub/sub channels send each message only where it is needed, at the price of keeping routing state up to date as users connect, disconnect and move between gateways.

The playground connects a million users across a fleet of gateways and sends 20,000 messages a second, either one-to-one or to groups of 50.

Messages go to

1 million users connected across 50 gateways, and 20,000 messages a second, each to one person. Broadcasting makes every gateway read every message, 20,000 a second each however many gateways you add, and only 2% of what each receives is for its own users. A connection registry or per-user channels send each message only to the gateway that needs it: 400 a second per gateway, falling as the fleet grows. The registry pays one lookup per message; pub/sub moves that state into the broker’s subscriptions.

10/s100/s1K/s10K/s100K/s51050100500 gateways
broadcast: messages each gateway receivesregistry or pub/sub
Broadcast to all gatewaysevery gateway sees every message
Each gateway receives
20,000/s
Useful to it
2%
Inside the cluster
1 million/s
Registry lookups
none
Routing state
none
Connection registrylook up user → gateway, send directly
Each gateway receives
400/s
Useful to it
100%
Inside the cluster
20,000/s
Registry lookups
20,000/s
Routing state
1M user → gateway entries
Pub/sub channelsgateways subscribe per user or room
Each gateway receives
400/s
Useful to it
100%
Inside the cluster
40,000/s
Registry lookups
none
Routing state
1M subscriptions

What the numbers say

  • Broadcast does not scale out. Every gateway reads every message, 20,000 a second, whether there are 10 gateways or 500. With 50 gateways only 2% of what each one receives is for its own users, and the cluster moves a million messages a second to deliver 20,000.
  • Targeted routing scales with the fleet. With a registry or per-user channels each message goes to one gateway, so each of 50 gateways handles 400 a second, and adding gateways keeps reducing it. The registry costs a lookup per message; pub/sub keeps the same mapping as broker subscriptions.
  • Groups change the picture. A group of 50 spread over 50 gateways touches about 32 of them, so broadcast is less wasteful, 64% useful, and looking up every member costs a million registry lookups a second. Per-room channels, with each gateway subscribing once for all of its members in that room, deliver to just those gateways without per-member lookups.
  • Routing state must heal. Registry entries carry a time to live refreshed by heartbeats, so a crashed gateway’s users expire and reappear when they reconnect elsewhere; messages for users who are not connected anywhere are stored and trigger a push notification.

The moving parts

# on connect: the gateway records where the user is (registry) or subscribes (pub/sub)
SET conn:user:812 gw-17 EX 90          # refreshed by heartbeats, expires if the gateway dies
SUBSCRIBE user:812                     # or: SUBSCRIBE room:team-eng, once per room per gateway

# sending a direct message
gw = GET conn:user:812                 # registry: one lookup...
POST http://gw-17/deliver {to: 812, ...}   # ...then one targeted send
PUBLISH user:812 {...}                 # pub/sub: the broker knows who subscribed

# if the user is not connected anywhere: store it and send a push notification

In a system design interview

For chat, presence or live updates, say how a message finds the right connection: “Gateways hold the WebSockets and register each user in a connection registry with a TTL, refreshed by heartbeats. The chat service looks up the recipient’s gateway and forwards the message directly; for channels with many members, gateways subscribe to the channel on a pub/sub layer once for all their local members. Offline recipients get the message from storage on reconnect and a push notification now.” Expect the follow-ups: users connected on several devices, a gateway crash in the middle of a delivery, and ordering of messages within a conversation.

Read the guide to WebSockets vs SSE vs long polling or group chat fan-out, see real-time delivery and online presence, or watch a strong candidate design WhatsApp.

Questions people ask

How do you send a WebSocket message to a user connected to another server?

The server handling the message must find the gateway that holds the recipient’s connection: by looking it up in a connection registry such as Redis that maps users to gateways, or by publishing to a pub/sub channel that the gateway subscribed to when the user connected.

Why not broadcast every message to all WebSocket servers?

Because every server then processes every message, so per-server load stays the same as the fleet grows and most of the work is discarded. It is only reasonable for small fleets or for messages meant for almost everyone.

What is a connection registry?

A fast store mapping each connected user, or device, to the gateway holding their connection, written on connect and removed on disconnect, usually with a time to live refreshed by heartbeats so entries for crashed gateways expire.

Should I use Redis pub/sub for WebSocket fan-out?

It works well at moderate scale: gateways subscribe to channels for their users or rooms and Redis forwards messages only to subscribers. Redis pub/sub does not persist messages, so offline delivery needs separate storage, and very large deployments use sharded pub/sub or dedicated brokers.

How do group chats change WebSocket routing?

A group message must reach every gateway holding a member. Per-room channels, with each gateway subscribing once for all its local members, deliver to exactly those gateways without looking up every member on every message.

What happens when a WebSocket gateway crashes?

Its connections drop and clients reconnect, usually to another gateway, which registers them again. Messages sent in between are stored and delivered on reconnect, with sequence numbers so the client can ask for anything it missed.

How do you handle users connected on several devices?

Route by device or connection rather than by user: the registry holds a set of connections per user, and a message is delivered to each of them, while read state is synced through the server.