mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4162] [RFC]: Shared Low-Overhead RDMA Congestion Control for TE and TENT #1050
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#1050
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Bo-Vincent on GitHub (Sep 16, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4162
Originally assigned to: @alogfans, @stmatengss, @zxpdemonio on GitHub.
Changes proposed
Proposal
Introduce a default-off software congestion controller shared by the classic Transfer Engine (TE) and TENT. After the transport resolves the actual RDMA path and immediately before posting a WR, the controller applies byte-window admission to both the device and route domains. Existing modules continue to own batch submission, QoS ordering, endpoint lifecycles, and final transfer completion status.
The goals are to reduce avoidable network pressure and repeated use of unhealthy paths while keeping the additional fast-path cost measurable and removable. Failure classification determines recovery scope. It must not turn one slow transfer or a temporary quarantine into a claim that a peer has permanently failed.
Relationship to Existing Work
PR #2489 proposes per-device AIMD in a TENT runtime plugin, and its discussion calls for coordination between congestion control and QoS. This proposal moves byte reservation to the resolved RDMA post boundary, adds route-scoped failure handling, and shares one policy core between classic TE and TENT. It is an integration alternative, not a second controller that should be enabled independently beside that plugin.
RFC #2866 discusses hierarchical QoS budgets and work-conserving scheduling. The proposed composition is: QoS determines which tasks may run and in what order; the transport performs the final byte reservation on the selected device and route. When admission is denied, work remains with its existing queue owner. TENT continues to derive delivery rate from its existing posted/completed telemetry. A permit represents only a temporary admission reservation, not a second scheduling policy.
Before landing, the CC and QoS maintainers must agree on the hook location and a single policy authority. The current code and tests do not establish that this controller can be safely stacked with another unmerged controller.
Controller and Transport Responsibilities
This is software admission control. It neither implements DCQCN nor configures ECN or PFC. NIC-level congestion control remains independent.
Failure Model, State Machine, and Recovery
Failure handling must answer two separate questions: whether the current RDMA object remains reusable, and whether the corresponding route is temporarily pressured, suspected of failure, or persistently unavailable. A QP error may require immediate retirement of that QP, but it does not by itself prove that an entire NIC or remote node has permanently failed.
Failure Scope
FailureScopelimits how far the controller may isolate a failure. It does not take ownership of destroying or rebuilding existing QPs, CQs, or endpoints. Peer membership, leases, and global node removal remain responsibilities of metadata, the endpoint manager, and the upper control plane.Path State Machine
HEALTHY: normal admission; consecutive low-pressure successful epochs additively increase the window.CONGESTED: transfers still succeed, but drain time, backlog, or receiver pressure remains high; multiplicatively reduce the window without triggering failover.SUSPECT: route timeouts or QP/route hard errors have occurred but have not reached the threshold; stop growing the window and preserve existing recovery opportunities without declaring long-term unavailability.QUARANTINED: hard errors or timeouts reach the threshold, a CQ/port/device fatal event is observed, or a probe fails; reject new posts in the affected scope.PROBING: after cooldown, permit only a bounded probe on a new generation; success recovers from the minimum window, while failure returns to quarantine and starts a new cooldown.Late feedback from an old generation, an old endpoint, or a replaced QP may only settle the old accounting record. It cannot change the replacement path's state. Software timeouts observed while the poller is stalled are suppressed for that control epoch so CPU scheduling or an unconsumed CQ is not mistaken for a network failure.
Completion/WC Handling Matrix
IBV_WC_SUCCESSSuccess / operationCongestion / route or deviceCONGESTED; shrink only the window, without quarantine or rail replacementIBV_WC_RNR_RETRY_EXC_ERRReceiverPressure / QPIBV_WC_RETRY_EXC_ERR,IBV_WC_RESP_TIMEOUT_ERRRouteTimeout / QPSUSPECT; only threshold exhaustion or failure of a new-generation probe entersQUARANTINEDIBV_WC_LOC_LEN_ERR,LOC_PROT_ERR,MW_BIND_ERR,LOC_ACCESS_ERRLocalConfiguration / operationUNKNOWNIBV_WC_LOC_QP_OP_ERR,LOC_EEC_OP_ERR,LOC_RDD_VIOL_ERR,INV_EECN_ERR,INV_EEC_STATE_ERRLocalConfiguration / QPIBV_WC_BAD_RESP_ERR,REM_INV_REQ_ERR,REM_ACCESS_ERR,REM_OP_ERR,REM_INV_RD_REQ_ERR,REM_ABORT_ERRRemoteMetadata / operationIBV_WC_WR_FLUSH_ERRDerivedFlush / QP, not a root failureIBV_WC_FATAL_ERR,GENERAL_ERR,TM_ERR,TM_RNDV_INCOMPLETEFatal / QPvendor_errFatal / QPvendor_errvendor_erris retained only as diagnostic evidence. A nonzero value does not automatically expand failure scope.LocalConfiguration,RemoteMetadata, andDerivedFlushdo not enter the AIMD hard-error counters; their existing request, metadata, or teardown owners handle them.Async Event Handling Matrix
IBV_EVENT_QP_FATAL,QP_REQ_ERR,QP_ACCESS_ERRIBV_EVENT_WQ_FATAL,SRQ_ERRIBV_EVENT_CQ_ERRIBV_EVENT_PATH_MIG_ERRSUSPECTbelow the threshold and let the existing rail/failover owner select another pathIBV_EVENT_PORT_ERRIBV_EVENT_DEVICE_FATALIBV_EVENT_PORT_ACTIVE,GID_CHANGE,LID_CHANGE,PKEY_CHANGE, successful path migration, and other non-failure eventsNon-WC and Control-Plane Handling Matrix
tryAcquire = kDeferBYTE_WINDOW; task state isCONGESTEDtryAcquire = kAvoidon a quarantined pathPATH_QUARANTINED; task state isLONG_UNAVAILABLEUNKNOWNibv_post_sendor an equivalent API when the WR was not handed to hardwareRouteTimeout; rebuild the current QP/endpoint through the existing lifecycleSUSPECTand taskCONGESTEDbelow the threshold; long unavailability only after threshold exhaustion or probe failureUNKNOWN; avoid blaming the network for CPU scheduling delayGetSegmentDescRPC service failureREMOTE_METADATA/UNKNOWN; escalate only if the refreshed generation still times outDerivedFlushUNKNOWNLONG_UNAVAILABLEwith explicit quarantine/no-path evidence; otherwiseUNKNOWNRDMA_CM_EVENT_DISCONNECTED,UNREACHABLERDMA_CM_EVENT_DEVICE_REMOVALrdma_cm_idand isolate the local deviceMooncake does not add a second verbs event loop for this classifier. The completion path reuses existing
ibv_poll_cqcalls; the background path reuses existingibv_get_async_eventandibv_ack_async_eventhandling.ibv_query_qpandibv_query_portare allowed only on slow recovery paths for diagnostics, event handling, or pre-probe checks, never per request.A QP in RTS proves only local QP state. An ACTIVE port does not prove that the remote endpoint, GID, route, and rkey are consistent. NIC counters such as
PortXmitWait, ECN/CNP/PFC, and retransmissions are low-frequency supporting evidence only. A successful bounded data-plane probe on a new generation is the basis for declaring route recovery.Recovery Escalation
The congestion controller owns admission, quarantine, and recovery only at route/device scope. It neither turns a local RDMA failure into cluster membership removal nor bypasses existing transport failover.
Caller Observability
The controller's five internal states do not map one-to-one to the four caller-visible states.
HEALTHYnormally projects toNORMAL. Byte-window deferral, receiver pressure, congestion feedback, and a route timeout that has not caused quarantine project toCONGESTED.QUARANTINED, no usable path, or a failed probe project toLONG_UNAVAILABLE. Local configuration, remote metadata, derived flush, a terminal failure without usable path evidence, controller-off mode, and unsupported transports project toUNKNOWN.SUSPECTandPROBINGchange task state only when the task actually observes blocking or quarantine evidence; callers must not infer task state from a background state alone.NORMALBYTE_WINDOW,RECEIVER_PRESSURE,CONGESTION_FEEDBACK, orROUTE_TIMEOUTbefore quarantineCONGESTEDPATH_QUARANTINED,PROBE_FAILED,NO_USABLE_PATHLONG_UNAVAILABLELOCAL_CONFIGURATION,REMOTE_METADATA,DERIVED_FLUSH, orFATALwithout attributable current-path evidenceUNKNOWNThe admission boundary does not split a slice. An empty domain may admit one valid complete slice larger than the current window, including while probing. The full byte count is reserved and blocks further over-window admission until it drains. Therefore the adaptive bound is
max(window, one indivisible slice), not an absolute 64 KiB probe limit. Existing transport static limits still apply.The controller retains bounded anomaly evidence on the batch-owned logical task. Callers may query it read-only during the
(batch_id, task_id)lifetime:NORMAL,CONGESTED,LONG_UNAVAILABLE, orUNKNOWN.LONG_UNAVAILABLEmeans the current path remained unavailable through quarantine or recovery evidence; it does not prove permanent HCA or peer damage.Classic TE and TENT expose identical semantics through C++ and C, and the existing TENT Python binding provides both minimal and detailed queries. The interface is transport-neutral, but the first implementation records congestion evidence for RDMA only. Unsupported transports, controller-off mode, or insufficient evidence return
UNKNOWN. ExistinggetTransferStatusandtent_task_statuslayouts remain unchanged; this proposal does not add a combined*StatusExAPI.A later Mooncake-pro PUT integration may wait for completion, query a failed task before
free_batch, and carry the classification in its error path. Upper-layer product integration is not part of this RFC's first implementation.Configuration, Compatibility, and Rollback
The controller is compiled only with
MOONCAKE_ENABLE_ADAPTIVE_CC=ON; the default isOFF. A worker readsMC_ADAPTIVE_CC_MODE=off|observe|enforceat construction:off: bypass policy and admission state.observe: record signals and compute policy without deferring or avoiding work.enforce: apply byte admission and path quarantine.All state-machine parameters are adjustable before startup:
MC_ADAPTIVE_CC_MIN_WINDOW_BYTES/MAX_WINDOW_BYTESMC_ADAPTIVE_CC_TARGET_DRAIN_USMC_ADAPTIVE_CC_HIGH_PRESSURE_EPOCHS/LOW_PRESSURE_EPOCHSMC_ADAPTIVE_CC_HARD_ERROR_THRESHOLDMC_ADAPTIVE_CC_COOLDOWN_MSMC_ADAPTIVE_CC_PROBE_WINDOW_BYTESPROBINGEvery numeric value must be positive. The minimum window must not exceed the maximum, and an explicitly configured probe window must not exceed the minimum window. An invalid setting fails worker initialization and leaves the controller off rather than continuing with a partially defaulted configuration.
Rollback currently means draining requests and restarting with mode
off; changing process environment variables does not hot-switch existing workers. Compile-timeOFFremoves controller fields and code. Consumers and libraries that exchange transport types must use matching public C++ layouts. CMake dependencies must propagate the CC compile definition; manually compiled ON/OFF objects must not be mixed.The TENT Python extension ships in the existing Mooncake wheel rather than a separate version chain. A TENT build places the extension and runtime dependencies in the
mooncakepackage and retains compatibility with top-levelimport tent. Installation acceptance must run from a fresh environment using the repaired wheel, not a build-directoryPYTHONPATH.Performance Acceptance
Proposed gates are at most 1% regression when the controller is compiled in but runtime mode is
off, and at most 3% large-transfer throughput regression for healthyenforce. These are acceptance targets, not conclusions established by a single observation.Comparisons among compile-out, runtime off, observe, and enforce must fix the HCA, peer, firmware, CPU/NUMA placement, message sizes, workload, and measurement interval. Each arm starts from independent process, queue, and connection state, or applies an identical documented warm-up. Record source and binary identities, CPU cost, throughput, latency tails, queue peaks, actual controller state, and payload correctness. Report small-message costs separately. In addition to healthy bulk transfer, test incast, route recovery, and multi-NIC failure.
The CPU microbenchmark measures the controller, not end-to-end request p99. Soft-RoCE can verify software paths but cannot qualify physical-HCA performance or fabric behavior.
Before submitting a new issue...
@github-actions[bot] commented on GitHub (Sep 16, 2026):
Thanks for opening this issue, @Bo-Vincent!
205891898A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide