21. Polling vs WebSockets vs Push
21.3 How do you scale millions of open connections?
At the gate: A call centre with thousands of open lines. Each operator can hold many quiet lines at once. When the kitchen has news for customer 881, someone has to know which operator is holding 881's line.
In the system: SSE and WebSockets mean one open connection per user, for minutes or hours. At 1 million users, that's 1 million connections held at once. Three problems:
1. Connections per server. Each idle connection costs memory (buffers, TLS state, your own per-user data) and a file descriptor. If one costs about 20 KB (an assumption: measure your own), 1 million connections need about 20 GB of memory across your servers. Event-driven servers (Node.js, Go, Netty, Erlang/Elixir) handle large numbers of mostly idle connections well. Raise OS limits like open file descriptors, and keep per-connection work tiny.
2. Which server holds which user? The order service knows "order 881 is packed", but Asha's connection is on gateway 1 of 10. Two common patterns:
- Pub/sub backplane: every gateway subscribes to a shared channel (Redis pub/sub, Kafka, NATS); the order service publishes "user Asha: packed", and the gateway holding Asha delivers it (Chapter 23).
- Connection registry: store "Asha → gateway 1" in a fast store and send the message to that gateway directly. More efficient at huge scale, but the registry must stay accurate as users reconnect.
Figure: gateways only hold sockets; a backplane routes each message to whoever holds the user.
3. Load balancing and deploys. A long-lived connection sticks to one server, so:
- Load balancers must support long timeouts and the WebSocket upgrade; balance by connection count, not requests.
- A new server gets no traffic until clients reconnect; a deploy drops thousands of connections at once. Drain gracefully: stop accepting new connections, tell clients to reconnect elsewhere, then shut down.
- Separate the connection gateways from business logic, so you can deploy business code without dropping everyone's connection.
Memory code: "Gateways hold the lines; the backplane knows who's on which."