WebSocket Performance
Long-lived connections.
WebSocket performance characteristics
WebSocket performance is the discipline of accepting that long-lived, bi-directional, stateful connections impose costs unlike request-response HTTP. The cost model is different; the operational shape is different.
- Long-lived connections. Per-connection memory and file-descriptor cost; scales with concurrent users, not request volume.
- Bi-directional. Server push without polling; fewer round trips than HTTP polling for live updates.
- Stateful. Per-connection server affinity; load balancing is sticky or requires shared state across instances.
- Keepalive ping. Periodic ping per connection catches half-open sockets the TCP layer never reports.
Scaling considerations
Scaling WebSockets is its own discipline. File descriptors, memory, kernel tuning all matter; defaults are sized for HTTP, not for hundreds of thousands of long-lived connections.
- Connections per server. Tens of thousands by default; with tuning, hundreds of thousands; the wall is FDs and memory, not CPU.
- File descriptor limits.
ulimit -nmust be high; default 1024 is far too low; bump to 65k+ for production. - Memory per connection. Kilobytes per connection; connection count drives total memory; budget at 16-32 KB per socket.
- Kernel tuning.
somaxconn,tcp_mem,ip_local_port_range; defaults assume request-response, not long-lived.
Operating WebSocket services
Operating WebSocket services is its own discipline. Sticky routing, graceful drain, per-connection metrics all matter; the request-response operational playbook does not transfer.
- Sticky load balancing. Connection state lives at one server; routing must be consistent for the connection lifetime.
- Graceful drain on deploy. Connection-close discipline per deploy; clients reconnect to the new pod; no abrupt drops.
- Per-connection metrics. Connection count, message rate, latency per server; aggregate hides per-connection issues.
- Auth refresh. Token rotation mid-connection; long-lived sessions outlive token TTLs; the protocol must support refresh.
When not WebSocket
WebSocket is overkill for many patterns. SSE, HTTP/2 streams, and long polling each fit specific cases better; pick the simpler primitive when it works.
- Server-sent events. One-directional push; HTTP-based; works through any proxy that handles HTTP; simpler than WebSocket.
- HTTP/2 streams. Request-response with push; standard infrastructure handles it; no special LB rules needed.
- Long polling. Low-frequency updates; simpler than WebSocket; works through restrictive corporate proxies.
- Pattern matching. Pick the protocol that matches the workload; WebSocket is the heaviest tool, not the default tool.