Mooncake Transfer Engine 传输层:MultiTransport 如何选择 TCP、RDMA 和设备路径

梳理 MultiTransport 的安装与后端选择流程,说明 TCP、RDMA 和设备传输如何接入统一接口。

Code walkthroughsMooncake and HiCache internalsLLM servingKV cacheMooncakeTransfer Engine

Transfer Engine 的上层接口很统一,但真正的数据搬运要落到具体传输方式。Mooncake 通过 MultiTransport 统一不同后端。

读这一层时,重点不是背下每种传输后端的实现细节,而是理解选择链路:

text
TransferRequest
  -> MultiTransport
  -> selected Transport
  -> RDMA / TCP / EFA / NVLink / device backend

object mapping

MultiTransport 不能只根据协议选择路径

选择传输方式时,要同时看 Segment 元数据、已安装后端、本地缓冲区注册状态和路径本地性。

TransferRequest

操作码、本地地址、目标 ID、偏移量和长度

Segment 元数据

目标位置和协议提示

协议te_endpointSegment ID是否在同一节点

已安装的传输后端

当前环境中真正可用的实现

TCPRDMAEFANVLink厂商后端

最终路径

最终执行的搬运方式

本地内存复制RDMA READ/WRITETCP 传输设备路径

installTransport 决定可用后端

TransferEngine 暴露:

text
installTransport(proto, args)
getTransport(proto)
uninstallTransport(proto)

协议标识可以对应不同实现。常见路径包括:

text
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 中包含协议和节点信息。

简化关系:

text
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 的职责。

排障时不要把传输成功当成整个系统正确。完整链路需要同时满足:

text
元数据正确
副本可读
租约有效
缓冲区已注册
传输成功
HiCache commit 成功

性能边界

传输层常见的瓶颈包括:

  • 页太小,批量提交和完成通知的开销过高。
  • 缓冲区未提前注册,导致热路径上临时注册。
  • 选择 TCP 而不是 RDMA/NVLink。
  • NIC/NUMA 不匹配。
  • 批次内的目标过于分散,无法有效聚合。
  • 主机内存布局不适合零拷贝分页传输。

这些问题最终会让 HiCache 的远端命中变慢,甚至比重新做预填充还慢。

传输成功只是整条链路的一部分

排查 Mooncake + HiCache 时,传输层要回答的是“这批数据能否以合适的成本完成传输”,而不是“这段远端 KV Cache 能否被注意力计算复用”。前者需要看后端是否安装、Segment 协议是否匹配、本地缓冲区是否注册、设备和 NUMA 配置是否合理;后者还要继续检查 Store 副本、租约、从 page key 到对象键的映射,以及 HiCache 回载。

同机路径尤其容易误判。能走 TCP 不代表应该走 TCP;如果直接复制内存就能完成,绕一圈协议栈只会让数据路径更复杂。反过来,跨节点 RDMA 路径如果选错设备,即使功能正确,尾延迟也可能吞掉远端命中的收益。

所以传输层的结论通常不能只写成“成功/失败”,还要回答:当前路径是否符合部署预期,是否避开了热路径注册,以及批次中的缓存页对象是否得到足够高效的聚合处理。