发表时间: 2025-10 · arXiv:2510.27656
原文: https://arxiv.org/abs/2510.27656
作者/机构: Nandor Licker, Kevin Hu, Vladimir Zaytsev, Lequn Chen
一句话结论 本文提出了可移植的 RDMA 点对点通信库 TransferEngine,通过统一异构网络硬件的无序交付机制打破了云厂商硬件锁定,在解耦式推理、强化学习权重更新和混合专家模型路由中实现了业界领先的通信性能。
要解决什么问题 原有大语言模型系统高度依赖 NCCL 等集体通信库,这类库要求通信成员固定、必须同步初始化且传输缓冲区大小统一,导致解耦式推理、混合专家模型(MoE)路由和异步强化学习微调等需要动态、稀疏点对点通信的场景卡在灵活性上。虽然基于远程直接内存访问(RDMA)的点对点通信能解决此问题,但现有高性能实现(如 NVSHMEM)深度绑定特定硬件。具体而言,传统硬件(如 NVIDIA ConnectX)的 RC 协议提供有序交付,而云厂商硬件(如 AWS EFA)的 SRD 协议本质是无序交付。这种底层机制的割裂导致开发者无法用一套代码在不同云环境中榨干网络带宽,严重制约了新兴模型架构的跨平台部署。
怎么做的 核心思路是放弃对网络消息有序到达的依赖,提取异构 RDMA 硬件“可靠但无序交付”的共性,构建统一的点对点通信抽象层 TransferEngine。为绕开底层协议在排序保证上的差异,该方法引入了核心原语 IMMCOUNTER。它不依赖操作顺序,而是通过轮询底层完成队列并在批量接收到带有立即数的数据后递增计数器,以原子化方式向接收方传递完成通知。在架构上,TransferEngine 为每个 GPU 分配固定在同 NUMA 节点的工作线程,透明管理多个网络接口控制器(NIC),将单次传输切片并负载均衡到多个网卡上,从而在 AWS 实例上聚合四个 100 Gbps 网卡跑满 400 Gbps 带宽。其关键部件包括:第一,双边 SEND/RECV 接口,通过循环缓冲区池处理小载荷的 RPC 风格通信;第二,单边 WRITE 接口,支持零拷贝的连续或分页内存写入;第三,统一虚拟内存观察者(UVM Watcher),通过在内存中分配标志位让 CPU 线程持续轮询 GPU 状态,一旦检测到 GPU 内核执行进展就立即触发网络传输,在缺乏硬件级异步通信支持的设备上实现了计算与通信重叠。针对 MoE 路由场景,方法进一步设计了基于主机代理的调度与合并机制,先交换极小的路由信息并投机性地将少量令牌发送到私有缓冲区以隐藏网络延迟,随后再将大批量令牌直接写入连续的共享接收缓冲区,避免了为每个 rank 分配上限为 $N \cdot T \cdot \max(R, E)$(其中 $N$ 为 rank 数,$T$ 为令牌数,$R$ 和 $E$ 为路由专家和总专家数)的庞大独立接收缓冲区,大幅减少了内存占用和写入次数。
效果如何 实验在配备 8 块 H200 GPU 的节点上进行,网络硬件对比了单卡 400 Gbps 的 ConnectX-7 和双卡 200 Gbps 的 EFA。对比基线包括英伟达官方点对点库 NIXL、基于 NVSHMEM 的 pplx-kernels,以及代表 MoE 路由最高水平但深度绑定 ConnectX 的 DeepEP。在基础通信中,TransferEngine 仅需 64 KiB 分页写入即可跑满带宽,性能略优于 NIXL。在异步强化学习微调中,该方法通过全网卡并行的单边写入,将万亿参数模型从 256 张训练卡到 128 张推理卡的权重更新时间压缩至 1.3 秒,比现有全局集体通信框架快 100 倍以上。在 MoE 解码路由测试中,该方法在 16 和 32 卡节点间场景下击败 DeepEP 创下 ConnectX-7 最低延迟纪录,同时首次让 EFA 具备了可用性(延迟仅比 ConnectX-7 高 30%),且比 pplx-kernels 快一个数量级。代价与局限在于:由于高度依赖主机 CPU 代理,扩展到 64 卡时 CPU 调度开销会显著增加;此外,这套为解码优化的内核在处理大批量预填充任务时,因未像 DeepEP 那样利用 NVLink 进行节点内局部求和来减少网络传输量,存在较高内存开销,预填充延迟不如 DeepEP。
本文旨在解决新兴大语言模型(LLM)系统中点对点通信的硬件可移植性问题。
核心问题: 新兴的LLM系统模式,如解耦式推理(disaggregated inference)、专家混合(MoE)路由和异步强化学习微调,需要灵活的点对点通信,而不仅仅是简单的集体通信(collectives)。现有的LLM框架主要依赖NCCL等集体通信库,这些库存在成员固定、需要同步初始化和缓冲区大小统一等限制,不适用于动态和稀疏的通信模式。虽然高性能计算领域早已使用基于RDMA的灵活通信原语,但在LLM框架中,由于云服务商(如AWS EFA)和传统硬件(如NVIDIA ConnectX)提供的RDMA实现不同(例如,EFA SRD协议是无序交付,而ConnectX RC协议是有序交付),导致缺乏统一的抽象,现有解决方案存在供应商锁定问题。
研究目标与创新点: 本文的目标是开发一个可移植的RDMA通信库,以弥合不同RDMA硬件之间的功能差距。
IMMCOUNTER原语。主要贡献与应用展示: 作者通过三个生产系统展示了TransferEngine的有效性,证明了点对点通信能够补充集体通信,同时保持高性能和可移植性。
RDMA: 远程直接内存访问(RDMA)是现代机器学习系统的核心,提供高吞吐、低延迟的网络通信。目前部署的NIC可提供400 Gbps带宽和亚微秒级延迟。RDMA通过分离控制平面(初始化设备和缓冲区,需操作系统参与)和数据平面(数据传输和完成轮询,绕过内核)来实现高性能。
RDMA操作: RDMA提供双边和单边操作。双边SEND/RECV操作需要接收方先发布一个带有注册内存区域的RECV,然后发送方发出SEND,并通过完成队列通知接收方。单边WRITE操作将本地内存复制到远程内存区域,无需对端参与,但需要远程内存地址和密钥(RKEY)。WRITEIMM是WRITE的扩展,它在传输数据的同时传递一个32位立即数,并同样通过完成队列通知接收方。READ和原子操作因延迟较高,不适用于本文的场景【12, Reda et al., RDMA is turing complete, we just did not know it yet!, 2022, NSDI】。
RDMA传输协议: RDMA规范定义了三种传输协议:可靠连接(RC)、不可靠连接(UC)和不可靠数据报(UD)。表1总结了它们的特性,并指出本文的TransferEngine是它们之间的共同基础。
云RDMA适配器: 除了广泛部署的ConnectX系列,主要的云提供商也在部署自己的解决方案,如AWS弹性光纤适配器(EFA)、阿里云eRDMA和Google Falcon。虽然大多数与RC兼容,但EFA实现了专有的SRD协议,该协议通过libfabric接口暴露【29, Shalev et al., A cloudoptimized transport protocol for elastic and scalable HPC, 2020, IEEE Micro】【25, OFIWG, libfabric: Open Fabrics Interfaces (OFI), 2014】。SRD是无连接的,提供可靠但无序的交付。
集体通信: 机器学习框架主要依赖集体通信库(如torch.distributed, NCCL, MPI)进行GPU间数据交换【15, Li et al., PyTorch Distributed: Experiences on accelerating data parallel training, 2020, Proc. VLDB Endow.】【23, NVIDIA, NVIDIA collective communication library (NCCL), 2015】【21, MPI Forum, MPI: A Message-Passing Interface Standard Version 5.0, 2025】。虽然集体操作擅长结构化数据传输,但其点对点能力有限:(1) 固定成员:要求预先知道所有参与者,阻碍了动态扩展;(2) 同步初始化:需要全局协调来形成“通信世界”,阻塞了独立的对等连接;(3) 操作排序:要求所有参与者就操作序列达成一致,即使NCCL支持并发接收也需要额外的同步【10, Hu et al., Demystifying NCCL: An in-depth analysis of GPU communication protocols and algorithms, 2025b】;(4) 形状统一:即使是点对点传输,也限制了所有参与者的传输大小。
GPUDirect: GPUDirect RDMA允许RDMA NIC通过PCIe直接访问GPU内存,消除了中间的CPU内存拷贝【22, NVIDIA, GPUDirect RDMA, 2012】。传输可以由主机发起,或者在支持GPUDirect Async(IBGDA)的情况下,由GPU自己发起以绕过PCIe开销【1, Agostini et al., GPUDirect async: Exploring GPU synchronous communication techniques for InfiniBand clusters, 2018, J. Parallel Distributed Comput.】。目前,GPUDirect Async仅在ConnectX NIC上受支持。此外,GPUDirect RDMA通过GDRCopy库实现了低延迟的主机-设备memcpy【32, Shi et al., Designing efficient small message transfer mechanism for inter-node MPI communication on InfiniBand GPU clusters, 2014, HiPC】。
解耦式推理: Splitwise【26, Patel et al., Splitwise: Efficient generative LLM inference using phase splitting, 2024, ISCA】, DistServe【44, Zhong et al., Distserve: Disaggregating prefill and decoding for goodput-optimized large language model serving, 2024, OSDI】, 和Mooncake【27, Qin et al., Mooncake: Trading more storage for less computation — a KVCache-centric architecture for serving LLM chatbot, 2025, FAST】是最早展示解耦式推理架构优势的工作,它们将LLM推理的预填充和解码阶段分离到不同设备上。本文的KvCache传输用例通过TransferEngine将预填充和解码集群通过RDMA连接起来,实现了这一范式。
点对点网络库: NVSHMEM同时提供了集体操作和灵活的点对点通信【14, Langer et al., Dynamic symmetric heap allocation in NVSHMEM, 2021, OpenSHMEM】。它支持GPU发起的(IBGDA)和主机代理(IBRC)通信,但在EFA上性能严重下降。NVIDIA Inference Xfer Library(NIXL)针对LLM推理的P2P通信,基于UCX构建【24, NVIDIA, NIXL: NVIDIA inference xfer library, 2025】【30, Shamis et al., UCX: an open source framework for HPC network APIs and beyond, 2015, IEEE】。本文在生产中部署的EFA实现早于NIXL(v0.6.1,2025年10月)中初步的EFA支持。Mooncake也提供了一个RDMA传输引擎,但不支持EFA。其他库如UCCL【19, Mao et al., Previewing UCCL-EP: Flexible and efficient expert parallelism for cloud and beyond, 2025】和MSCCL++【28, Shah et al., Msccl++: Rethinking gpu communication abstractions for cutting-edge ai applications, 2025】则专注于对集体操作进行网络层优化,而非点对点通信。
分布式KvCache存储: Mooncake Store和DeepSeek 3FS【5, DeepSeek AI, Fire-flyer file system (3fs), 2025】提供了KV Cache的分布式存储,但目前缺乏EFA支持。本文通过提供适用于云部署的可移植RDMA原语来补充这些系统。
计算与通信重叠: 关于LLM内核中计算与集体通信重叠的研究【4, Chang et al., Flux: Fast software-based communication overlap on gpus through kernel fusion, 2024】【41, Zhang et al., COMET: Fine-grained computationcommunication overlapping for mixture-of-experts, 2025】【42, Zheng et al., Sglang: Efficient execution of structured language model programs, 2024】【43, Zheng et al., Tritondistributed: Programming overlapping kernels on distributed ai systems with the triton compiler, 2025a】与本文关注的RDMA原语是正交的,尽管本文也支持后台传输。
LLM框架: 本文的TransferEngine和MoE内核可以集成到vLLM, SGLang, TensorRT-LLM, FlashInfer等LLM推理框架和内核库中【13, Kwon et al., Efficient memory management for large language model serving with pagedattention, 2023, SOSP】【42, Zheng et al., Sglang: Efficient execution of structured language model programs, 2024】【23, NVIDIA, TensorRT-LLM, 2023】【40, Ye et al., FlashInfer: Efficient and customizable attention engine for LLM inference serving, 2025】。本文的P2P权重更新方法可以被Slime, OpenRLHF, AReaL, veRL, LlamaRL, NVIDIA Nemo等强化学习框架采用【36, Wu et al., LlamaRL: A distributed asynchronous reinforcement learning framework for efficient large-scale LLM training, 2025】【45, Zhu et al., slime: An llm post-training framework for rl scaling, 2025】【7, Fu et al., Areal: A large-scale asynchronous reinforcement learning system for language reasoning, 2025】【20, Mei et al., Real: Efficient rlhf training of large language models with parameter reallocation, 2025】【31, Sheng et al., Hybridflow: A flexible and efficient rlhf framework, 2024】【9, Hu et al., Openrlhf: An easyto-use, scalable and high-performance rlhf framework, 2025a】。
TransferEngine是一个基础库,它通过抽象异构硬件,在一个简单的协议下实现高效的基于RDMA的点对点通信。它暴露了SEND/RECV操作来实现类似RPC的接口。对于KvCache传输,它提供分页WRITEs用于批量写入。对于RL权重传输,它暴露了低延迟高吞吐的WRITE操作。对于MoE路由,它特化了针对多个对端的WRITEs,以实现低延迟的SCATTER和BARRIER操作。所有操作之间没有任何排序保证。一个立即数可以与WRITEs关联,在接收方收到数据后递增一个计数器。
核心设计:TransferEngine暴露了一个最小化的API,抽象了底层RDMA接口的复杂性。它支持多种接口,包括使用SRD协议的EFA和可通过libibverbs编程的多种NIC(包括ConnectX-7)。它能透明地检测拓扑以处理每个GPU的多个NIC:单个ConnectX-7 NIC提供400 Gbps带宽,而在AWS p5实例上实现同等带宽需要聚合四个100 Gbps的EFA NIC。单个实例会跨多个线程来管理一个节点内所有的GPU和NIC。通过零拷贝接口和硬件特定优化实现低延迟操作。
解决排序差异:为了弥合RDMA RC的有序保证和EFA SRD的无序交付之间的差距,TransferEngine完全依赖一种新颖的IMMCOUNTER机制。它不依赖排序保证,所有完成通知都通过轮询完成队列并在批量接收到立即数值后传递通知来处理。通知通过回调函数或原子标志传递。
架构图示:图1展示了TransferEngine的架构。该引擎为每个GPU派生一个工作线程(worker),每个工作线程管理一个通用的DOMAINGROUP,该DOMAINGROUP协调所有关联的RDMA NIC(通常为1-4个,取决于硬件平台)。在一个通用的DOMAINGROUP内,每个DOMAIN都针对特定硬件进行了特化,负责单个NIC,处理队列对管理、工作提交和完成轮询。
地址交换与传输分片:每个TransferEngine实例暴露一个主地址用于身份识别和远程对端发现。我们使用一个NetAddr结构体来捕获和序列化一个DOMAIN的网络地址,并在希望通信的对端之间交换该结构。一个限制是,所有对端每个GPU必须使用相同数量的NIC。因此,任何传输都完全了解源和目标域之间的NIC情况,这使得TransferEngine可以对请求进行分片或均衡。这对于E-FA至关重要,因为它使用多个适配器来实现完整的400Gbps带宽。
TransferEngine暴露的API(如图2所示)实现了对RDMA的抽象:
#[serde] struct NetAddr(Bytes);
#[serde] struct MrDesc{ ptr: u64, rkeys: Vec<(NetAddr, u64)> }
struct MrHandle(NonNull<c_void>);
type Offset = u64;
struct Pages{ indices: Vec<u32>, stride: u64, offset: Offset }
struct PeerGroupHandle(u64);
struct ScatterDst{ len: u64, src: Offset, dst: (MrDesc,Offset)}
enum OnDone { Callback(fn () -> ()), Flag(Atomic<bool>) }
trait TransferEngine {
fn main_address() -> NetAddr;
// 内存区域管理
fn reg_mr(ptr, len, device) -> (MrHandle, MrDesc);
// 双边 Send/Recv
fn submit_send(addr: NetAddr, msg: &[u8], cb: fn () -> ());
fn submit_recvs(len: u64, cnt: u64, cb: fn (&[u8]) -> ());
// 单边 Write
fn expect_imm_count(imm: u32, count: u32, cb: fn () -> ());
fn submit_single_write(len: u64, imm: Option<u32>,
src: (MrHandle, Offset),
dst: (MrDesc, Offset), OnDone);
fn submit_paged_writes(page_len: u64, imm: Option<u32>,
src: (MrHandle, Pages),
dst: (MrDesc, Pages), OnDone);
// 对一组对端的单边 Write
fn add_peer_group(addrs: Vec<NetAddr>) -> PeerGroupHandle;
fn submit_scatter(h: Option<PeerGroupHandle>, OnDone,
imm: Option<u32>, src: MrHandle,
dst: Vec<ScatterDst>);
fn submit_barrier(h: Option<PeerGroupHandle>, OnDone,
imm: u32, dst: Vec<MrDesc>);
// 用于 CPU-GPU 同步的观察者
fn alloc_uvm_watcher(cb: fn(u64,u64) -> ()) -> NonNull<u64>;
}
内存注册: 内存区域必须在引擎中注册,返回一个可序列化的MrDesc(可与对端交换以提交WRITEs)和一个本地MrHandle(用作传输源)。该API可以注册主机端缓冲区和GPU内存。在这些不透明类型背后,句柄携带了它们关联的所有NIC的地址,以及附加的特定于域的远程密钥列表,形式为(NetAddr, RKEY)对。
点对点传输: submit_send及其远程对应的submit_recvs封装了SEND/RECV操作,以暴露RPC风格的通信,用于交换小载荷。提交时会进行一次拷贝,以便调用者可以立即重用或释放缓冲区。接收操作会发布一个循环的缓冲区池来接收数据。每收到一条消息,一个缓冲区会暂时从池中取出,让回调函数无需拷贝即可处理。回调完成后,它会自动被重新发布。必须分配足够的缓冲区以避免拒绝消息。这些操作只使用域组中的第一个NIC。
单边写操作: submit_single_write和submit_paged_writes将数据从源缓冲区传输到目标缓冲区,分别写入由间接索引、步长和偏移决定的连续或分页区域。引擎将这些操作转化为可能多个零拷贝的单边RDMA WRITE操作,并在可用的NIC上进行分片和轮转。每次传输可以携带一个可选的32位立即数,以便在完成时通知接收方。传输完成通知会异步地传递给调用者。
组播与屏障: submit_scatter将源缓冲区的一个切片发送到对等组中的每个对端,并写入它们接收缓冲区的不同偏移处;而submit_barrier是一个仅含立即数的操作,用于对端通知。这些是围绕WRITE的优化封装,允许应用程序预先注册一个PeerGroup以进行低延迟的批量传输。传输在两个设备之间执行,用户需要协调系统中多个设备的操作。
UVM观察者: 为了让主机能够在GPU取得进展时发起传输,alloc_uvm_watcher注册一个回调函数,当内存中某个字发生变化时调用。它分配一个统一虚拟内存(UVM)位置,设备(包括CUDA图中的内核)可以更新该位置,然后一个CPU线程使用GDRCopy持续轮询它。由于不保证所有变化都能立即被观察到,回调函数被调用时会传入旧值和新值,使其能够响应GPU端的进展。
完成通知: 通知会为发送确认和接收完成两种情况传递,通过回调函数或原子标志。IMMCOUNTER是一个专用组件,负责跟踪每个立即数对应的计数器,这些计数器在从底层设备完成队列中检索到的事件上递增。事件在发送方传输完成后,以及在接收方完全交付带有立即数的载荷后生成,保证了原子性。计数器分配在与域工作线程相同的NUMA节点上。计数器可以透明地与GPU通过GDRCopy同步,可以直接通过轮询观察,也可以通过expect_imm_count注册后,在引擎内一个专用的独立线程上交给回调函数处理。所有同步都使用此类计数器实现,因为没有其他排序保证。
实现细节: 我们的TransferEngine用Rust实现,精心优化了内存分配、线程和同步以最小化延迟,从而实现高吞吐量。引擎为每个DOMAINGROUP派生一个工作线程,每个线程都固定到设备所连接的NUMA节点上的一个CPU核心,以最小化调度和内存访问延迟。特定于域的数据结构在核心固定后分配,以确保内存在正确的NUMA节点上保留。一个工作线程负责处理多达4个DOMAIN,每个DOMAIN管理一个NIC,而另一个专用线程负责轮询GPU以更新UVM观察者。跨线程通信通过无锁队列完成。
工作循环与分片: API将请求转发给为相应设备服务的DOMAINGROUP,其中第一个也服务于主机。在一个紧凑的循环中,域工作线程轮询新工作,优先提交新请求。根据硬件和配置,请求会在可用的DOMAIN之间进行分片和负载均衡。复合请求的第一个WRITE会立即发布到DOMAIN中NIC的发送队列。当新请求处理完后,工作线程会继续处理待处理的工作,发布writes以填满硬件流水线。随后,轮询完成队列以查询已完成的传输和立即数计数器增量。事件被聚合以传递每次传输的通知,并将传输交给所有组共享的一个专用回调线程。
分片灵活性: DOMAINGROUP内的分片是灵活的。传输可以通过索引指定特定的NIC。单个WRITE可以被拆分。分页传输、scatter和barrier操作都会转化为多个WRITEs,可以在所有NIC上进行分片。
TransferEngine内的DOMAIN针对其控制的硬件进行了特化和优化:
AWS EFA: 我们使用libfabric实现EFA支持,在DOMAINGROUP内为每个NIC管理一个fabric domain。由于EFA与RDMA规范不同,它对仅含立即数的零大小写入不要求有效的目标描述符,我们强制所有传输都使用有效的描述符。对于批量传输和对等组,我们采用工作请求(WR)模板化,在发布前预先填充并保留libfabric描述符的公共字段。
NVIDIA ConnectX-7: 我们通过libibverbs实现ConnectX支持。对于每个对端,我们使用一个UD队列对来交换RC握手信息。我们为每个对端创建2个RC队列对:一个用于双边SEND/RECV操作,另一个用于单边WRITE和WRITEIMM操作。这种分离是必要的,因为RECV和WRITEIMM完成都会按发布顺序消耗工作请求。这使我们能够在支持WRITEIMM的同时提供高层级的RECV语义而不产生干扰。除了WR模板化,我们还通过ibv_send_wr的next指针链接多达4个工作请求,从而采用WR链式操作,减少了对NIC的doorbell rings次数。此外,我们启用了IBV_ACCESS_RELAXED_ORDERING,允许NIC和GPU内存之间进行无序的PCIe事务,从而降低延迟。
本节概述了一个依赖TransferEngine、经过生产测试的解耦式推理实现。在解耦模式下,一个预填充(prefiller)节点对输入令牌运行预填充,并将生成的KV页以及任何额外上下文(如用于推测解码的最后一个令牌的隐藏状态和logits)传输到解码器(decoder)节点,解码器节点随后逐个解码令牌。
工作流程: 如图3所示,收到请求后,全局调度器选择一个预填充节点和一个解码器节点来处理它,并将请求转发给解码器。解码器预先分配KV页和任何上下文所需的存储空间,然后使用submit_send将请求分派到指定的预填充器,指示内容应传输到的KV页索引。
分块预填充与传输触发: 在分块预填充期间,我们在每层的注意力输出投影后递增UVM观察者的值,这与CUDA Graph兼容。一旦TransferEngine检测到UVM观察者值的变化,该层的传输就会启动,通过submit_paged_writes从当前块复制页面。当最后一个块完成并且上下文已填充后,它会通过submit_single_write被复制过去。预填充器使用submit_recvs等待命令。
处理分片差异: KV传输必须考虑预填充器和解码器之间KV缓存分片或复制的差异。MLA【18, Liu et al., Deepseek-v2: A strong, economical, and efficient mixture-of-experts language model, 2024】在使用张量并行时会复制压缩的KV缓存条目:在这种方案下,预填充器的rank会与解码器的rank随机匹配,以平衡副本的传输。在GQA【2, Ainslie et al., Gqa: Training generalized multi-query transformer models from multi-head checkpoints, 2023】下,我们依靠页级偏移和步长从源KV缓存中选择切片,复制到目标KV缓存的相应偏移处。为最小化写入次数并确保单个写入足够大,KV缓存的布局是头(heads)在页(pages)之前,以确保障连续头内的连续性。
完成与错误处理: 预填充器不发送明确的完成消息:解码器预先知道它期望的传输数量,并使用expect_imm_count来由TransferEngine通知传输完成并开始解码。生产级解耦解码实现的复杂性在于错误和取消的处理。由解码器触发的取消必须由预填充器明确确认,因为只要存在远程写入覆盖它们的可能性,KV页就不能被重用。我们依靠预填充器和解码器之间的心跳消息来检测传输层故障。如果预填充节点无响应,请求在解码器上超时后被取消,因为传输无法再到达它。每个请求的取消令牌可以停止所有未来的传输,同时在发送取消确认之前等待所有挂起的操作。
在异步强化学习微调中,训练和推理在不同的GPU上运行。每次训练步骤后,新权重必须被推送到推理节点,对于万亿参数模型,使用现有框架可能需要几十到几百秒。我们的解决方案为Kimi-K2(1T参数)、DeepSeek V3(671B)和Qwen3(235B)等规模的模型实现了1.3秒的跨机器参数更新【12, Kimi Team et al., Kimi k2: Open agentic intelligence, 2025】【6, DeepSeek-AI et al., Deepseek-v3 technical report, 2025】【37, Yang et al., Qwen3 technical report, 2025】,将权重从256个训练GPU(bf16)传输到128个推理GPU(fp8)。
方法对比:现有框架倾向于为所有训练和推理GPU形成一个全局集体通信世界。权重被收集到训练子组的Rank0,然后广播到每个推理子组的Rank0,这受到训练Rank0的NIC瓶颈限制。相比之下,在我们的P2P方法中,每个训练GPU通过单边RDMA WRITE直接向推理GPU发送权重,从而利用了所有NIC的全部集群带宽。图4展示了这两种方法的区别。
初始化步骤:在初始化时,控制器脚本执行三个步骤:首先,它从所有训练和推理GPU收集参数元数据,包括权重名称、形状、数据类型和DTensor分片信息。其次,它计算一个静态的权重传输计划,映射哪个训练GPU将哪个参数发送到哪个推理GPU,以及发送顺序。最后,它将该计划广播给所有训练GPU。在每个训练步骤,控制器向训练GPU发信号开始发送权重。由于使用单边操作,推理节点对传输过程无感知。
并行化策略:我们的训练任务使用FSDP【41, Zhao et al., PyTorch FSDP: Experiences on scaling fully sharded data parallel, 2023】对模型权重进行分片。不同类型的参数(例如MoE与非MoE)需要不同的FSDP分片策略。每种分片策略将全局DeviceMesh划分为不相交的子网格(sub-mesh)。我们将每个子网格称为一个MeshGroup。MeshGroup内的参数并行传输,而MeshGroup之间则顺序处理。
四阶段流水线: 我们将每个参数张量的传输视为一个任务。为同时利用不同硬件资源,我们将每个任务分为四个时间上重叠的流水线阶段,如图5所示:(1) 主机到设备memcpy,如果FSDP将权重卸载到CPU;(2) 参数准备:使用full_tensor()重建完整权重,应用投影融合,如果需要则进行量化;(3) RDMA传输:零拷贝WRITE到远程推理GPU内存;(4) 全局屏障:在所有full_tensor()调用完成后,通过以太网使用GLOO在网格组之间同步。
内存管理:full_tensor()和其他GPU操作会引入额外的GPU内存使用。为避免内存不足错误,我们仅在当前正在进行的任务占用的临时GPU内存少于一个可配置的水印时才启动新任务。
我们介绍了一套围绕TransferEngine构建的用于MoE调度和合并的低延迟内核,它依赖一个主机代理线程来协调GPU和NIC。在节点内,我们还利用NVLink来减少网络负载。尽管代理线程增加了延迟,我们在保持预填充性能有竞争力且无需任何调整的情况下,实现了业界领先的解码性能。这些内核展示了基于代理的MoE调度在支持更广泛网络卡(如EFA)上的可行性。因此,我们专注于解码性能(每个rank 128个token),因为它受延迟限制,并且更容易受到跨设备增加的PCIe、驱动和固件开销的影响。
设计概览: 路由是使用分离的内核实现的,用于调度和合并。发送方的一半将数据准备到发送缓冲区以写入对端,接收方的一半则将来自接收缓冲区的令牌重排到其他内核使用的张量中。单个内核充分利用所有SM和GPU的内存带宽以减少延迟,但它们的运行时间足够短,可以在其间插入其他工作,从而实现重叠和微批处理。主机代理使用GDRCopy轮询GPU的进度,在源缓冲区就绪时调用TransferEngine。
减少开销:我们的设计(如图6所示)通过减少发出的写入次数来最小化代理开销。为了减少发送和接收缓冲区所需的GPU内存,所有对端首先交换路由信息(即每个专家的令牌计数),以确定一个连续接收缓冲区中的唯一范围进行写入。由于这些载荷很小,它们的延迟可以通过投机性地将少量令牌分派到私有的每个源的缓冲区中来隐藏。合并操作仅发出一个scatter,因为它重用了路由信息。路由信息总是由TransferEngine处理,但载荷可以在同一节点内通过NVLink复制。因此,对于每个节点间的对端,每个rank在调度时最多发出2次WRITE,在合并时发出1次WRITE。
缓冲区大小:接收缓冲区的大小必须能容纳发送到当前rank的所有令牌。假设有$N$个rank,每个rank上有$E$个专家,每个rank将$T$个令牌分派给$R$个专家,那么上限是$N \cdot T \cdot \max(R, E)$。发送方将写入打包到这样一个连续的缓冲区中,而不是依赖于更大的每个rank的接收缓冲区。为了最小化开销,较大的调度接收缓冲区可以被合并发送重用。
调度流程: dispatch内核接收令牌和它们必须被路由到的$R$个专家的索引,返回一个张量,该张量打包了分配给本地专家的所有rank的令牌。该内核首先在共享内存中计算发送到每个专家的令牌数量,并通过统一内存将计数传输到主机。然后它通知代理,代理使用TransferEngine启动向所有对端rank的路由scatter。输入令牌随后被复制到发送缓冲区,创建一个连续的源,以便scatter到每个对端,如图7所示。
延迟隐藏: 代理被通知将最多固定数量的令牌scatter到每个接收端对端的私有缓冲区中。对于解码大小的批次,从dispatch内核启动到第一次传输的延迟大约为15 µs(假设EP=64)。此时,路由和令牌的传输使NIC带宽饱和。一旦接收到路由并且可以在每个目标rank上确定来自每个源rank的令牌位置,剩余的令牌就被scatter到对端,将它们连续地放入共享的接收缓冲区。主机端处理路由和分派第二轮传输的工作需要几十微秒。初始传输中的令牌数量被选择来隐藏这个开销。虽然这个延迟不在关键路径上,但减少它可以进一步减小私有缓冲区的大小。一旦所有传输被确认为已完成并且所有传入的写入都已记账,一个屏障通过TransferEngine同步代理。
NVLink传输与同步: 在通过RDMA向节点间对端分派传输后,发送内核继续通过NVLink发出写入,以在同一节点内传输令牌,而RDMA传输在后台挂起。NVLink对端通过它们自己的一组屏障进行同步:在写入对端之前,每个rank必须确保数据已被读取并且可以被覆盖。这是通过使用松散语义写入和读取的标志来完成的。在载荷写入后,rank之间通过release-acquire标志进行同步。
写操作排序优化: 由于内存屏障的粒度不足,发送内核中的写入顺序对延迟至关重要。NVLink通过虚拟内存暴露,透明地将对映射到当前地址空间的对端设备的读写操作转换为互连上的事务。加载操作通常开销很大,因为它们会阻塞执行流水线直到满足。相比之下,存储操作是“即发即忘”的,直到遇到内存屏障,该屏障会阻塞直到其范围内所有先前的存储完成。由于主机系统和NVLink对端都在同一范围内,确保与主机排序的屏障可能会被先前通过NVLink发出的写入减慢。为避免这种情况,我们首先向主机发信号,然后在网格屏障后发出NVLink写入。这个策略增加了发送内核的总执行时间,但减少了到第一次RDMA传输的关键路径上的延迟。
NVLink读写策略: 使用NVLink时,通常最好从源设备向目标推送数据,以节省一次往返时间。此外,在当前设备上确认存储后,可以在传输到远程设备的过程中执行有用的工作。在dispatch阶段,我们只将令牌推送到私有接收缓冲区,因为此时中心化的路由信息尚不可用,无法确定其余令牌在对端上的确切位置。内核的接收部分通过在屏障上同步并读取剩余的令牌来启动。这些加载很可能在RDMA操作之前完成。
接收端处理: 在dispatch发送后,传输在后台运行。当接收内核被调用时,它等待TransferEngine通过IMMCOUNTER和GDRCopy报告所有传输的完成。依靠基于路由信息计算的索引,令牌被重新排序,并根据适用于分组GEMM内核的布局在专家之间进行可选的填充。由于接收内核必须在关键路径上处理大约$T \cdot R$个令牌,工作被分配到所有可用的SM上,并最大化流水线以充分利用可用的HBM带宽。
合并流程: 由于路由信息在dispatch阶段是中心化的,combine操作通过一次scatter传输所有载荷。命令在发送和合并之间的空闲时间内准备好,在此期间GPU通常会执行一个分组GEMM。发送方与dispatch类似,准备发送缓冲区并通过NVLink向节点内对端推送令牌。主机代理被通知向TransferEngine发送SCATTER请求,之后内核完成执行。接收方在等待所有令牌接收完毕之前,将所有从路由信息派生的相关偏移缓存在共享内存中。然后,在每个rank上本地计算令牌的加权平均值。
资源重用与同步: combine阶段重用了与dispatch阶段相同的缓冲区,因此它需要一个NVLink屏障和一个RDMA屏障,以确保在覆盖发送缓冲区之前所有先前的操作都已完成。此时,主机代理也等待TransferEngine确认所有写入都已发送出去。特别是对于EFA,它还需要等待接收确认,因此最大化发布写入和检查其状态之间的时间间隔非常重要。
对比分析: DeepEP提供了业界领先的延迟,但由于依赖IBGDA和mlx5驱动,它们被绑定在ConnectX上。我们的内核更具可移植性,依赖于主机代理,同时支持EFA和ConnectX。尽管有额外的开销,我们的延迟超过了DeepEP。
实现差异: DeepEP内核依赖于RC QP的强排序保证。令牌在可用的SM之间平衡,并通过一个QP逐个传输。这确保了到第一次传输的延迟较低,但也意味着每个令牌需要更多的工作,并导致通过网络发送更多的包。令牌计数和完成通过ATOMICs进行信号。相比之下,我们的内核在第一次传输发起前花费更多时间,因为有额外的GPU-CPU-NIC通信开销(通过PCIe)。然而,批量传输实现了更好的网络利用率。
预填充性能: 对于预填充,我们无需调整即可扩展我们的单次传输策略。相比之下,DeepEP通过在发送节点上使用NVLink预累积令牌来获得更好的延迟,减少了传输的数据量。此外,DeepEP内核使用的缓冲区内存更少,因为令牌的子集是分批传输的。虽然这种方法更快,但它也对准确性和确定性有影响,因为累积并不完全在fp32上以固定顺序完成。
硬件配置:
软件配置:
实验负载:
现有的用于LLM系统的RDMA解决方案存在供应商锁定问题,尤其是在AWS EFA等定制云硬件上缺乏可行的实现。本文提出的TransferEngine通过识别异构RDMA硬件间的共同功能(可靠但无序的交付)来解决这一问题。通过在底层协议之上构建一个不依赖排序保证的可靠抽象层,我们透明地将支持扩展到多种RDMA NIC,特别是EFA和ConnectX。
我们通过三个生产系统展示了这种方法的有效性:用于解耦式推理的KvCache传输、为万亿参数模型实现1.3秒更新的RL权重更新,以及在ConnectX-7上实现业界领先延迟并在AWS EFA上首次实现可行性能的MoE调度/合并。TransferEngine为现代LLM架构提供了可移植的点对点通信能力,在补充集体通信库的同时,避免了供应商锁定,尤其适用于云原生部署。