This document details the architectural design and technical implementation of the Eaze WebSocket server.
Eaze WebSocket is designed from the ground up for high-concurrency scenarios. It avoids the common pitfalls of traditional NIO implementations by distributing the workload across multiple specialized components.
Standard Java NIO implementations often rely on a single Selector to manage all connections. At high scales (100k+ connections), the internal synchronization of the Selector becomes a bottleneck. Eaze WebSocket utilizes a Multi-Poller architecture:
- MasterPollers: A pool of threads dedicated to
accept()operations and the initial HTTP-to-WebSocket handshake. This ensures that new connection attempts are never blocked by existing traffic. - SubPollers: Multiple independent poller threads, each managing its own
Selectorand a subset of active connections. This sharding strategy parallelizes I/O readiness checks and significantly reduces lock contention.
Eaze WebSocket leverages Java 21+ Virtual Threads to achieve a "one-thread-per-message" processing model without the memory overhead of platform threads.
- I/O Notification: A
SubPollerthread detects that a channel is ready for reading. - Virtual Thread Handoff: The
SubPollerimmediately spawns a Virtual Thread to handle the read operation and message decoding. - Non-Blocking Selection: While the Virtual Thread processes the message, the
SubPollercontinues to check other connections. The interest for the active connection is temporarily disabled to prevent concurrent reads on the same socket. - Re-Registration: Once processing is complete, the Virtual Thread re-enables the interest for the socket in the
SubPoller'sSelector.
To minimize GC overhead, the system employs a Direct Buffer Pool:
- Zero-Copy Intent: By using
ByteBuffer.allocateDirect(), the server interacts directly with the OS network stack, avoiding unnecessary data copying between JVM heap and native memory. - Pooled Resources:
ByteBufferinstances are recycled through aConcurrentLinkedQueue-based pool, preventing the expensive allocation of direct memory for every message.
The FrameCodec implementation provides efficient encoding and decoding of WebSocket frames as per RFC 6455. It handles:
- Text and Binary frames.
- Masking (for client-to-server messages).
- Control frames (Ping, Pong, Close).
- Fragmentation (continuation frames).
- Handshake: Performed synchronously by
MasterPollersto ensure only valid WebSocket connections enter theSubPollerpools. - Keep-Alive: Leverages TCP Keep-Alive and WebSocket Ping/Pong to maintain long-lived connections through middleboxes.
- Graceful Shutdown: Ensures all connections are closed with the appropriate status codes before the server stops.
- Context Switching: Minimized by using a fixed number of platform threads for polling and lightweight virtual threads for logic.
- Lock Contention: Reduced by sharding connections across
SubPollersand using thread-safe non-blocking queues for registration. - Memory Footprint: Each connection's state is kept minimal. Buffers are only held during active I/O.