fabric-lib: RDMA Point-to-Point Communication for LLM Systems
Nandor Licker, Kevin Hu, Vladimir Zaytsev, Lequn Chen
Perplexity AI
cs.DC
2025-11-01
Perplexity 开源跨网卡通信库 fabric-lib,用无序 WriteImm 统一 ConnectX 与 AWS EFA,峰值 400 Gbps。万亿参数 RL 权重 1.3 秒推到推理卡,MoE 解码在 ConnectX-7 赶上 DeepEP,EFA 上首次达到可用延迟。
LLM 系统现在大量依赖点对点通信。prefill 和 decode 拆到不同机器之后要搬 KvCache;MoE 要把 token 按专家打散再收回来;异步 RL 要把训练侧刚更新的权重推到推理卡。这些模式跟 NCCL 擅长的静态集合通信对不上号。
集合通信要求固定成员、同步建组、缓冲区形状一致。动态扩缩 prefiller 和 decoder 会卡在建组上,稀疏的 MoE 路由会被均匀 buffer 逼成稠密传输。NCCL 也暴露了 Send/Recv,拼不出可用延迟。
HPC 这边 RDMA 的单边 Write 早就能做低延迟大带宽传输。卡住的是网卡不统一。NVIDIA ConnectX 走可靠连接 RC,保序;AWS Elastic Fabric Adapter(EFA)走自研 SRD,可靠但不保序。DeepEP 绑死 GPU 发起的 IBGDA,只有 ConnectX 有;NVSHMEM 在 EFA 上掉得很厉害;Mooncake 和 NIXL 当时要么没有 EFA,要么还是雏形。云上两家网卡没法共用一套通信库。
Perplexity 的切入点很具体:ConnectX 的 RC 可以主动忽略保序,EFA 的 SRD 本来就不保序,两边的公共子集是「可靠但不保序」。fabric-lib 的 TransferEngine 就建在这个子集上。
核心原语是带 32 位立即数的单边 WriteImm,再配一个 ImmCounter。接收端在完成队列里按立即数累加,攒够约定数量再通知上层,不依赖报文到达顺序。正确性靠 PCIe 写序:WriteImm 的数据先于立即数发出,CPU 看到计数达标后再向 GPU 发后续事务,交换机能保证 GPU 已经看到数据。
引擎用 Rust 写,每个 GPU 一个 worker,绑在对应 NUMA 核上。多网卡对应用透明:ConnectX-7 一张卡就是 400 Gbps,AWS p5 要四张 100 Gbps EFA 绑在一起才到同样带宽,p5en 是两张 200 Gbps。传输按网卡分片轮转。EFA 走 libfabric,ConnectX 走 libibverbs,后者把 Send/Recv 和 WriteImm 拆到两条 RC 队列,避免完成队列互相抢。GPU 进度靠 UVM watcher:CUDA Graph 里的 kernel 改一个统一虚拟内存字,CPU 用 GDRCopy 轮询,触发下一层传输。整套是 host proxy,不走 GPU 直发 RDMA。
三个已经上线的用法:
评测两套机器:8×H200、每卡 2×200 Gbps EFA;8×H100、每卡 400 Gbps ConnectX-7。
| 操作 | EFA | ConnectX-7 |
| 单次 Write 256 KiB | 54 Gbps | 116 Gbps |
| 分页 Write 64 KiB | 364 Gbps | 370 Gbps |
| 单次 Write 32 MiB | 336 Gbps | 378 Gbps |
分页 64 KiB 接近 KvCache 一页,两边都能吃满带宽。单次 Write 要到 16 MiB 才饱和,这也解释了 MoE 那种 256 KiB 报文在 EFA 上吃不满。跟当时的 NIXL v0.6.1 比,TransferEngine 略快。
KvCache 用 Qwen3-235B、H200 TP4,页大小 32 kB(128 token)。16K 序列非分离 TTFT 929 ms,分离后 1042 ms;逐层传输 1.61 ms,同层计算 9.86 ms,传输被算力盖住。TTFT 变慢主要来自推理引擎多跑了一次最后输入 token 的 decode,不是 RDMA。Rust 侧 UvmWatcher 回调 p50 是 6.2 µs。
RL 权重:Kimi-K2 约 1T 参数,256 张训练卡 BF16(FSDP/PP/EP=16/2/8)推到 128 张推理卡 FP8(EP=32)。单 rank 总耗时 1233 ms。关键路径是 fulltensor 反分片 518 ms、等其他 rank 357 ms;RDMA 提交 26 ms(1144 个 WR),流水线盖不住的传输只剩 42 ms。DeepSeek-V3-671B 和 Qwen3-235B 的训练日志在 1.2-2 s。对照现有框架公开的 10-100 s,差一个数量级。引言写「超过 100 倍」,按他们给的对照区间,更接近 8-80 倍。
MoE 端到端(DeepSeek-V3,MTP,EP=DP=64,tokens/s):
| 集群 | 实现 | batch=2 | batch=8 | batch=32 |
| H200 EFA | Ours | 66.8 | 56.5 | 32.0 |
| H200 EFA | pplx-kernels | 21.0 | 11.6 | 4.9 |
| H100 CX-7 | Ours | 78.4 | 67.7 | 36.1 |
| H100 CX-7 | DeepEP | 73.8 | 65.8 | 36.3 |
EFA 上相对 NVSHMEM 那套 pplx-kernels 是 3-6 倍,论文称这是 EFA 上第一套可用延迟。ConnectX-7 上跟 DeepEP 持平或略快,尽管走的是 host proxy 不是 IBGDA。
微基准 decode、EP64:dispatch 本方案 CX-7 190 µs、DeepEP 180 µs;combine 311 µs 对 327 µs。EP16 和 EP32 两边 dispatch、combine 都更快。EP64 dispatch 慢在代理线程给 56 个跨节点 peer 入队,每个大约 1 µs。EFA decode 延迟大约落后 ConnectX 30%。Prefill 上 DeepEP 更强,尤其 combine:发送端先做部分求和,RDMA 字节少很多,累加精度掉到 bf16。
这是一套已经在生产里跑过三种模式的可移植点对点层,不是又一个只在 ConnectX 上刷延迟的 kernel。AWS 上做分离推理、MoE 服务、异步 RL 的团队,以前几乎没有能用的选择。
集合通信该继续用在张量并行、数据并行这种静态模式上。动态成员、稀疏路由、单边推权重,走这套更合适。代码开源在 pplx-garden,API 不绑网卡;后面接 eRDMA、Broadcom 这类 RC 兼容卡,应用层不用改。
它是渐进工程,不是新算法。价值在于把「可靠但不保序」当成一等公民,把多网卡聚合和完成通知做成可复用原语。
论文讨论写得很清楚:GPU 发起 RDMA 在多数云实例上还没有(AWS p5/p5e、eRDMA),p5en 也只是雏形,host proxy 是迁就现状。下一代宽 NVLink 域(GB200 NVL72)会把 MoE 通信从 RDMA 上挪走,这套对 MoE 的长期价值会缩。KvCache 和 RL 权重的 RDMA 已经被计算盖住,CPU 代理不伤端到端。
Prefill 没有 DeepEP 那套节点内 NVLink 复制和发送端部分求和。decode 向 kernel 也不做分块,接收缓冲按最坏情况预留,能部署的模型范围更窄。所有 peer 必须每 GPU 网卡数相同。Read 和原子操作故意没做,延迟不合适。
端到端跑在自研 PyTorch 推理引擎上,跟 vLLM、SGLang 的 DeepEP 集成不是同一套运行时。NIXL 后来也加了初步 EFA 支持,可移植性优势会随时间变薄。RL「100 倍」那句对照的是 10-100 s 的公开数字,分母跨了一个数量级,不宜当精确倍数引用。