-
Notifications
You must be signed in to change notification settings - Fork 0
Data Plane and Failover en
简体中文: Data-Plane-and-Failover · English
Control failover and weighted routing are two Hassium networking features that solve the "freeze / disconnect / rejoin" experience players hit when the master connection hiccups on multiplayer servers, and share the chunk-download load when a busy server saturates its bandwidth. The two work together: failover keeps players almost unaware when the master connection has issues, and weighted routing spreads chunk-download traffic across multiple lines.
These are two of the capabilities listed on the Home page:
| Feature | Description |
|---|---|
| Control failover | On TCP-control stall or drop, auto-reconnect via candidate endpoints with warm cache and hidden disconnect screen (data-plane failover) |
| Weighted routing | Multiple UDP/KCP endpoints carry the data plane by weighted round-robin; control plane stays on vanilla TCP |
Problem 1: The master connection hiccups, everyone drops to the main menu.
In vanilla Minecraft, login, chat, commands, and entity sync all ride one TCP master Play connection, and chunk downloads share that same line. When the master connection stalls for a few seconds (network jitter, server restart, machine migration) or drops, the client shows a "Connection lost" screen, kicks players to the main menu, loses cache, and rejoining means re-downloading every chunk. A few players are deep in a cave; the owner restarts for routine maintenance; everyone's progress looks "wasted".
Control failover does this: when the master connection stalls or drops, the client follows the candidate list the server pre-delivered and auto-connects to the next reachable endpoint, without showing a disconnect screen. Already-downloaded chunk cache and the task executor are kept; the new session resumes directly — the explored terrain is still in cache, hit ratio does not drop.
Problem 2: Hundreds of players log in at once and the master connection saturates.
The bottleneck on high-population servers is often chunk downstream: every player pulls a patch of terrain and one line cannot keep up. Scaling out also means worrying that one flaky line will take the server with it.
Weighted routing does this: chunk downloads run on a UDP/KCP data plane that can be configured with multiple endpoints (multiple lines), sharing load by weight (weighted round-robin). If one line fills or degrades, traffic shifts onto the rest. Login and commands — "control-class" traffic — stay on vanilla TCP and are untouched by data-line issues.
These two features are off by default — network.dataPlane.enabled = false, and the mod uses vanilla single-TCP behavior with normal co-op untouched. When you need control failover or public weighted routing, enable them as follows:
- Server-operator capability with Nginx / public-firewall / NAT rules;
- Set
network.dataPlane.enabled = trueinhassium-server.tomland configure reachable public endpoints; - Verify the six self-check markers in order (see the bottom of this page).
⚠️ The production env config for this feature is still being migrated; it is currently driven byDataPlanePoCConfigas a stopgap. Operators without these capabilities can leave it off — the other features are unaffected.
For solo friend co-op or small private servers: leave it off and skip the rest of this page. The technical details below target server operators with ops needs.
The following targets server operators with ops capability. Regular players can skip to FAQ for common questions.
| Plane | Purpose | Protocol |
|---|---|---|
| Control plane (Master TCP) | Vanilla Minecraft login + Play Connection | TCP |
| Data plane (UDP/KCP) | Chunk bulk and data-plane fan-out | UDP/KCP (independent sessions with KCP ReliableDatagramSession) |
- The control-plane endpoint list is delivered via S2C handshake tail (host:port + priority)
- The client mixes bootstrap + advertised endpoints, sorted by priority descending, up to 4 candidates (
ControlEndpointManager.MAX_CANDIDATES) - Each
(host, port)UDP endpoint binds an independent KCPReliableDatagramSession - The client issues a separate BindRequest per advertised endpoint with an HKDF-derived AES-GCM key
Hard disconnect: the Master TCP channelInactive → ControlReconnectOrchestrator.onPrimaryDisconnected immediately launches the next candidate; the client enters a 60-second recovery window.
Master stalled + UDP healthy: the server detects a control stall (default 6 seconds). During the stall, DataPlaneUdpServer.recordControlActivity advances; if the UDP session is healthy (matching epoch) the server issues a FailoverPermit (expiryMs default 30 seconds). The client only connects via attemptConnectOnlyIfPermitValid.
When ClientRecoveryState.shouldSuppressFinalization() is true, ClientLifecycleHelper.finalizeDisconnectIfTerminal short-circuits finalizeDisconnect, preserving:
- Disk cache
CacheSaveQueueHassiumTaskExecutor- Dirty flags
When the next candidate session starts, the cache is ready to use and the hit ratio does not drop.
ClientPlayConnectionEvents.DISCONNECT calls DataPlaneClientLifecycle.stopUdp(/*keepLease*/ true), so the UDP bundle is not released immediately.
ControlReconnectOrchestrator.performTerminalFinalization calls ClientLifecycleHelper.finalizeDisconnectIfTerminal; the singleton ClientRecoveryState.consumeTerminalCleanup guarantees exactly-once disk-resource cleanup.
The data plane supports multiple UDP endpoints sharing chunk-bulk traffic by weight (weighted round-robin):
- One
ReliableDatagramSessionper endpoint - WRR over
weight -
share/exclusiverouting modes - UDP health feeds into weight adjustment (degraded demotion)
| Key | Default | Notes |
|---|---|---|
network.dataPlane.enabled |
false |
Data-plane master switch (off by default; configure reachable endpoints and verify the six self-check markers in order before enabling) |
network.dataPlane.controlStallMs |
6000 |
Stalled-master duration before the client sends FailoverRequest
|
network.dataPlane.failoverPermitTtlMs |
30000 |
Validity window for the server-issued FailoverPermit
|
network.dataPlane.udpEndpoints |
(pending toml) | Candidate list; each item has host, port, weight, optional priority
|
udpEndpointsis currently delivered via the S2C tail; it cannot be hand-edited inhassium.tomluntil the production migration lands.
- Each public
udpEndpointsendpoint needs a public-UDP firewall/NAT rule - The 10-second UDP
leaseonly drains in-flight data; no new player data is produced before login completes -
controlStallMsrequires the server to issueFailoverPermit; the client does not open a second master Play connection based on latency alone - TCP control endpoints and UDP endpoints are separate lists; their public ports may differ
- Nginx
streamreverse proxy can carry TCP master + UDP-direct failover (see the self-check procedure below)
| Marker | Meaning |
|---|---|
UDP_BIND_OK |
Server UDP endpoint binds successfully |
UDP_WRR_OK |
Weighted round-robin dispatch is correct |
FAILOVER_PERMIT_OK |
Server can issue a permit under stall + UDP healthy |
FAILOVER_RECONNECT_OK |
Client can switch to the next candidate per the permit |
CACHE_RESUME_HIT |
Disk cache resumes after switch; hit ratio does not drop |
FAILOVER_TERMINAL_OK |
On candidate exhaustion, finalize exactly once |
With network.dataPlane.enabled = false, no UDP listener / bind / failover behavior should occur (regression guard).
Hassium · GitHub · CurseForge · GPL-3.0-or-later