Mooncake Transfer Engine 传输层:MultiTransport 如何选择 TCP、RDMA 和设备路径
梳理 MultiTransport 的安装与后端选择流程,说明 TCP、RDMA 和设备传输如何接入统一接口。
Transfer Engine 的上层接口很统一,但真正的数据搬运要落到具体传输方式。Mooncake 通过 MultiTransport 统一不同后端。
读这一层时,重点不是背下每种传输后端的实现细节,而是理解选择链路:
TransferRequest
-> MultiTransport
-> selected Transport
-> RDMA / TCP / EFA / NVLink / device backend
object mapping
MultiTransport 不能只根据协议选择路径
选择传输方式时,要同时看 Segment 元数据、已安装后端、本地缓冲区注册状态和路径本地性。
TransferRequest
操作码、本地地址、目标 ID、偏移量和长度
Segment 元数据
目标位置和协议提示
已安装的传输后端
当前环境中真正可用的实现
最终路径
最终执行的搬运方式
installTransport 决定可用后端
TransferEngine 暴露:
installTransport(proto, args)
getTransport(proto)
uninstallTransport(proto)
协议标识可以对应不同实现。常见路径包括:
tcp
rdma
efa
nvlink
intranode nvlink
hip / ascend / vendor-specific backend
某个后端是否真的可用,取决于编译选项、运行环境、设备发现和配置。文档中写明支持某种协议,不代表当前构建一定启用了它。
MultiTransport 的职责
MultiTransport 不是新的传输协议。它是路由和聚合层。
它需要做几件事:
- 管理已安装的传输后端。
- 根据协议或 Segment 信息找到目标后端。
- 把批量传输拆给对应后端。
- 汇总批次状态。
- 在多协议场景下处理注册内存和提交任务。
这一层让 Store 和上层框架不必关心每个后端的具体类名和状态查询方式。
内存注册也要区分后端
registerLocalMemory 看起来是一个统一 API,但对不同传输后端有不同含义。
RDMA/EFA 可能需要注册内存区域和 rkey/lkey。NVLink 或 GPU 后端可能要处理设备指针、IPC 句柄或执行流。TCP 可能不需要同等级的硬件注册,但仍要接入统一接口。
因此,注册内存不是可选优化,而是数据传输协议的一部分。
对 HiCache 与 Mooncake Store 的组合来说,主机 KV 池必须在 Store 初始化后完成注册。否则,即使零拷贝读写拿到了指针,底层传输后端也不一定能够使用。
本地路径不能盲目走 TCP
同机或同节点的传输不一定应该走 TCP 回环。Mooncake 的注释特别指出,即使只安装了 TCP 后端,同一主机内的数据传输也可能更适合直接复制内存。
原因很直接:本地 memcpy 少了一层协议栈,也避免把同进程或同节点的数据搬运伪装成网络传输。
这也是 Store 的 TransferSubmitter 要判断数据本地性的原因。并非所有副本都需要通过 Transfer Engine 走网络传输。
传输方式取决于 Segment 信息
Store 副本指向 Segment,Segment 中包含协议和节点信息。
简化关系:
Replica
-> Segment
protocol
te_endpoint
id
offset
TransferSubmitter 根据副本和 Segment 构造 TransferRequest 后,Transfer Engine 再根据目标 Segment 与协议找到传输后端。
如果 Segment 协议、Transfer Engine 节点、已注册内存和已安装后端彼此不匹配,就会出现“Store 中明明有对象键,数据却搬不回来”的问题。
RDMA 路径要看设备选择
RDMA 和 EFA 这类路径还涉及网卡、NUMA、设备筛选和自动发现。设备选错可能导致:
- 注册内存失败
- 对端连接失败
- 带宽远低于预期
- 跨 NUMA 访问导致尾延迟抖动
SGLang Mooncake 后端复用共享 Transfer Engine 也有严格条件,例如协议、元数据服务器和设备名称都要匹配。条件不满足时,HiCache Mooncake Store 会创建自己的 Store 客户端,而不是盲目复用 PD 分离式推理使用的 Transfer Engine。
传输层不负责对象一致性
传输层只知道任务成败,不会判断:
- 这个对象键是不是最新。
- 副本是否为 COMPLETE。
- 租约是否过期。
- K/V 对象是否同属于一个逻辑页。
- 辅助内存池是否一起命中。
这些是 Store 和 HiCache 的职责。
排障时不要把传输成功当成整个系统正确。完整链路需要同时满足:
元数据正确
副本可读
租约有效
缓冲区已注册
传输成功
HiCache commit 成功
性能边界
传输层常见的瓶颈包括:
- 页太小,批量提交和完成通知的开销过高。
- 缓冲区未提前注册,导致热路径上临时注册。
- 选择 TCP 而不是 RDMA/NVLink。
- NIC/NUMA 不匹配。
- 批次内的目标过于分散,无法有效聚合。
- 主机内存布局不适合零拷贝分页传输。
这些问题最终会让 HiCache 的远端命中变慢,甚至比重新做预填充还慢。
传输成功只是整条链路的一部分
排查 Mooncake + HiCache 时,传输层要回答的是“这批数据能否以合适的成本完成传输”,而不是“这段远端 KV Cache 能否被注意力计算复用”。前者需要看后端是否安装、Segment 协议是否匹配、本地缓冲区是否注册、设备和 NUMA 配置是否合理;后者还要继续检查 Store 副本、租约、从 page key 到对象键的映射,以及 HiCache 回载。
同机路径尤其容易误判。能走 TCP 不代表应该走 TCP;如果直接复制内存就能完成,绕一圈协议栈只会让数据路径更复杂。反过来,跨节点 RDMA 路径如果选错设备,即使功能正确,尾延迟也可能吞掉远端命中的收益。
所以传输层的结论通常不能只写成“成功/失败”,还要回答:当前路径是否符合部署预期,是否避开了热路径注册,以及批次中的缓存页对象是否得到足够高效的聚合处理。