Node.js Socket.IO Server ↔ Official JavaScript Client: Is Concurrent-Load Latency a Transport or Adapter Decision?
0 reputation · 24 Dec 2022, 00:18 UTC
0 reputation · 24 Dec 2022, 00:18 UTC
A Socket.IO 4.x server on Node.js, paired with the official JavaScript client, must be sized for a workload where latency is expected to surface only when concurrent connections and emits ramp up. The open decision is where such latency would belong: the Engine.IO polling-to-WebSocket upgrade path, the single process's event loop, or the multi-node adapter layer.
Two documented behaviors frame it. Socket.IO starts with HTTP long-polling and upgrades to WebSocket unless configured otherwise; forcing websocket-only removes upgrade overhead but changes proxy, firewall, and fallback behavior. With polling enabled, one session's polling requests must reach the node holding that session, so sticky sessions enter the picture. Scaling out with the Redis adapter adds serialization and pub-sub hops and does not make emits globally ordered.
Constraints: knobs such as maxHttpBufferSize, permessage-deflate, and acknowledgement timeouts are version-sensitive, so any comparison needs a pinned version matrix, with client runtime, proxy, and adapter layers separated before attributing anything to the protocol.
Open questions:
33275 reputation · 24 Dec 2022, 01:08 UTC
When latency appears only as concurrent connections and emits increase, the dominant source is usually the adapter layer (e.g., Redis pub/sub), not the Engine.IO transport upgrade. The upgrade from long‑polling to WebSocket causes a short, one‑time spike that disappears after the connection is established; steady‑state per‑message latency is governed by the Node.js event loop and, when an adapter is active, by the round‑trip to the adapter.
Under a steady stream of emits, each message must traverse the adapter hop. As the number of concurrent emits grows, the Redis server experiences more pub/sub traffic, increasing the round‑trip time and contributing to higher median and 95th‑percentile latency. The event loop may still be a factor if the server performs heavy work per message, but in typical emit‑only workloads the adapter hop is the primary scalability bottleneck.
adapter: null) and force WebSocket‑only connections (transports: ['websocket']). Run a load test with the target concurrent client count and measure per‑message latency (e.g., using performance.now() on the client and timestamps on the server).--trace-warnings or clinic flame to detect event‑loop blocking.Are you using sticky session load balancing for the polling fallback? If not, the observed latency may stem from missed session affinity rather than the adapter, and enabling sticky sessions would be the first corrective step.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.