mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4897] [RFC]: Same-Rail KV Cache Transfer via a Local Proxy GPU for Classic Transfer Engine #1244
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#1244
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 @yunjuanyunshu0902-zyh on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4897
Changes proposed
Proposal
Introduce a default-off cross-rail avoidance path in the classic Transfer Engine (TE) RDMA transport. When a slice originates on a GPU whose same-rail NIC is not usable for the chosen remote peer NIC, the sending host stages the payload on a locally reachable proxy GPU that shares a PCIe switch (and NVLink) with the source GPU and whose same-rail NIC can reach the remote peer NIC on the same rail. The transport issues one
cudaMemcpyAsyncfrom the source GPU to a pinned proxy-GPU slot, then issues the RDMA WRITE from the proxy GPU through its same-rail NIC. Receiver semantics, upper-layer transfer completion, and endpoint lifecycles remain unchanged.The goal is to remove cross-rail traffic from the spine fabric in PD-disaggregated inference. Spine switches are shared with other tenants, and cross-rail KV cache bursts observed in production trigger PFC pause-frame storms that propagate past the originating flow and degrade TTFT of co-located workloads. Keeping KV transfer traffic on the same rail eliminates the spine as a congestion domain for this workload without changing fabric configuration.
This proposal is scoped to the classic Transfer Engine RDMA transport. It does not change ECN or PFC settings, does not alter the TCP, EFA, UB, or TENT transports, and does not take ownership of peer liveness or cluster membership decisions.
Relationship to Existing Work
PXN relaying was first described in the NCCL communication library (
NCCL PXN): for a cross-rail GPU pair, egress through a locally reachable proxy GPU whose same-rail NIC can reach the remote peer on the same rail. This proposal applies the same locality principle to the Mooncake classic Transfer Engine data path. It is implemented as an opt-in build feature, keeps the existing RDMA worker pool as the submission authority, and reuses the existing endpoint, metadata, and completion lifecycles. It does not add a new transport, a new metadata channel, or a new control plane.Before landing, the TE RDMA maintainers must agree on the hook location in
submitTransferTaskandWorkerPool::submitPostSend, and on the fact that the PXN packing stage runs on the submit thread while slot admission and the actualibv_post_sendremain with the existing worker pool.Transport and PXN Responsibilities
PxnRuntimeManagerowns the following and nothing else:(src_gpu, local_nic)pair, the proxy GPU that is same-rail withlocal_nicand reachable fromsrc_gputhrough NVLink andnvidia_peermem. The map is built once atRdmaTransport::install()and is immutable at run time.ibv_reg_mron the proxy GPU, used only as a staging buffer for in-flight cross-rail slices.PxnPlanAndPack) that chooses between the native RDMA path and the PXN path based on peer buffer locality and source GPU affinity.PxnRunDispatcherOnce) that issuescudaMemcpyBatchAsyncon CUDA 12.8+, or falls back to acudaMemcpyPeerAsyncloop on earlier CUDA, from the user source buffer into the proxy slot, records a CUDA event, and hands the real RDMA slice to the worker pool once the event completes.nvidia_peermemloaded, and the peer buffer that holds the slice destination is itself registered as GPU memory on the remote side. If any condition is false the slice falls back to the native RDMA path and the controller never allocates a slot for it.bypass_requestslist for slices that cannot use PXN; the worker pool consumes those as ordinary RDMA requests. Topology-level unavailability (no NVLink,nvidia_peermemabsent, proxy GPU without GDR, oribv_reg_mrrefusing the slot pool) disables PXN for the affected scope at startup, and the native path handles every slice from that point on.PXN is a software staging policy. It does not change ECN or PFC on either host, and does not configure the NIC's internal congestion controls.
Data Flow and Control Hooks
Native path (unchanged)
PXN path (new, cross-rail only)
The PXN packing stage runs on the submit thread (the caller of
submitTransferTask). The dispatcher and the finalibv_post_sendrun on the worker pool's transfer worker threads. The data path never touches new atomics or new mutexes on non-PXN slices.Submit-side sharding of CW shells
Each CW's lifecycle, slot assignment, cascade pointer, and CUDA event are owned by exactly one worker thread, so no cross-thread coordination is needed inside a CW. The shard function is
where
worker_countequalsMC_WORKERS_PER_CTX(default 2). The scratch buckets used to batch per-shard pushes are thread-local on the submit thread; the sharedstate->pxn_slice_queue[shard_id]is protected by a per-shardTicketLock. There is no cross-submit-thread sharing of PXN state outside those shard locks.Build Options and Environment Variables
Build
USE_PXNOFFOFFstrips every PXN source file, header, andpxn_infofield from the build.ONcompiles the PXN runtime manager, topology manager, slot pool, and WorkerPool integration intolibmooncake-transfer-engine.Compile-time
OFFis the only supported way to remove PXN cost from a build. MixingONandOFFobject files in the same translation unit set is not supported.Runtime
MC_PXN_SLOT_SIZE_KB1024MC_PXN_SLOT_COUNT_PER_WORKER16workers_per_ctx * slot_count_per_worker * slot_size.MC_WITHOUT_PXN1, the PXN runtime path is bypassed even if PXN was compiled in. The topology and slot pool are still built; every slice takes the native path. Leave unset to enable PXN at run time.Both numeric variables expect a positive integer. A non-positive or malformed value is ignored with a warning, and the built-in default is used. If a worker cannot allocate the configured staging memory on a NIC, that NIC falls back to the native path with a warning; other NICs are unaffected.
Caller Observability
PXN does not change the return layout of existing
getTransferStatusortent_task_status()queries.TransferStatusEnumthe native path uses. The caller cannot tell from the status whether a slice was proxied; this is intentional. Transport selection is not part of the caller contract.task_completion_latency_us) covers both the PXN and native paths with no new bucket layout. No PXN-specific counter is added to the public metrics surface in this change.Configuration, Compatibility, and Rollback
MC_WITHOUT_PXN=1at TransferEngine construction. Existing workers are not hot-switched; the current process must be drained and restarted. Compile-timeUSE_PXN=OFFremoves every PXN field and code path, includingSlice::pxn_info, which is only exposed to callers through private layout.USE_PXNvalue, becauseSlice::pxn_infolayout changes. Consumers using the public C or TENT bindings are not affected (pxn_infolives in a private slot).RdmaTransportand the RDMAWorkerPoolonly. TCP, EFA, UB, kunpeng, cxl, and TENT paths are not touched.Performance Acceptance
Proposed gates:
USE_PXN=OFFUSE_PXN=ON, run withMC_WITHOUT_PXN=1USE_PXN=ON, run with PXN enabled, source and chosen peer NIC on the same railUSE_PXN=ON, run with PXN enabled, source and chosen peer NIC on different railsbench_serving, request rate 10 req/s, max concurrency 64, 100 requests, Mean/P50/P90/P95/P99 TTFT)Every comparison must fix HCA, firmware, GPU, CPU/NUMA placement, GPU-to-NIC PCIe topology, message size, and workload. Each arm starts from independent process, queue, and connection state, or applies an identical documented warm-up. Soft-RoCE may be used to validate the software paths but cannot qualify physical-HCA throughput.
Before submitting a new issue...
@github-actions[bot] commented on GitHub (Oct 23, 2026):
Thanks for opening this issue, @yunjuanyunshu0902-zyh!
64839424A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide