Traffic and messaging
Fan-out with pub/sub
How one message reaches thousands of connected users through a pub/sub backbone, why subscribing by interest beats routing to each user, and the write math for large channels.
Fan-out means one message reaching many recipients. In a chat system, a message to a channel with 2,000 online members must reach every gateway that holds one of those members' connections. The question is how the publisher finds those gateways without doing work per member.
The big idea
There are two designs. In route to user, the publisher looks up each recipient in the registry and sends to each one's gateway. In subscribe by interest, each gateway subscribes to the channels its users care about. The publisher sends once, and the backbone copies the message to each subscribed gateway. Each gateway then delivers to its local sockets.
Subscribe by interest is usually the better choice for group chat. The publisher writes once. The number of copies scales with the number of gateways, not the number of members.
Walking through it
Take a channel with 2,000 online members spread across 3 gateways.
Route to user:
for each of 2,000 members:
look up gateway in the registry → 2,000 lookups
publish to that gateway's topic → up to 2,000 publishesSubscribe by interest:
publish once to channel:general → 1 publish
backbone copies it to 3 subscribed gateways → 3 copies
each gateway writes to its local sockets → 2,000 socket writes, spread across 3 machinesThe second design moves the per-member work to the machines that already hold the sockets. Slack's architecture works roughly this way, with channel servers and gateway servers that subscribe to the channels they need.
Choosing a backbone matters:
| Backbone | Properties | Good for |
|---|---|---|
| Redis pub/sub | In memory, fire and forget. A subscriber that is down misses messages | Simple setups, typing and presence |
| Redis Streams | Persisted and replayable by ID | Resume buffers, small to medium scale |
| NATS and NATS JetStream | Very low latency, subject wildcards, optional persistence | Large fan-out meshes |
| Kafka | Durable and ordered per partition, high throughput | Feeding gateways from an event stream |
Do the fan-out math before choosing:
A 100,000-member channel that receives 10 messages per second, delivered per viewer:
100,000 × 10 = 1,000,000 socket writes per secondThat is why very large channels, such as a live sports feed, are often batched. One frame carries 20 messages every 200 ms, or the feed is sampled or rate-limited per viewer.
Common mistakes
- Routing to each user for large groups. Lookups scale with members, not with gateways.
- Using plain Redis pub/sub for messages that must arrive. A subscriber that is down misses them. Use a persisted backbone.
- Forgetting the write multiplier. Large channels multiply every message by the number of members.
Check yourself
-
A 100,000-member channel gets 10 messages per second, and each viewer gets each message. How many socket writes per second?
Answer: 1,000,000 (100,000 × 10).
-
Why does subscribe-by-interest beat route-to-user for a large group?
Answer: the publisher writes once per message, and the backbone copies it once per gateway, not once per member.
Key takeaways
- Subscribe by interest lets the publisher write once, while gateways deliver to their own sockets.
- Choose a backbone by its delivery guarantees, not only its speed.
- The socket-write count grows with members times messages, so batch or sample very large channels.
Further learning
Next, see how heartbeats and resumes keep these connections honest, in connection lifecycle.
Related
Queues vs pub/sub topics
Two ways to deliver a message. A queue gives each message to one worker. A topic gives a copy to every subscriber. Real systems use both.
Event streaming and Kafka
How a durable log lets many consumers read the same events at their own pace, and how Kafka builds that log from partitions, replicas and consumer groups.
Gateways and connection registry
Why real-time servers split into thin stateful gateways and stateless services, how a TTL registry finds the gateway holding a user, and how many connections one machine can hold.
Real-time delivery
How a server pushes updates to clients that did not ask, from polling to WebSockets, and the gateway, pub/sub and reconnect design that serves millions of open connections. Start here for the real-time map.