Mooncake Transfer Engine:内存段、注册内存和批量传输
从内存段、内存注册、传输请求和批次编号出发,建立 Mooncake Transfer Engine 的数据搬运模型。
Mooncake Transfer Engine 解决的问题很具体:给定本地缓冲区、远端 Segment、偏移量和长度,如何可靠地写入或读回一批数据。
它不理解对象键,不判断副本是否为 COMPLETE,也不知道这段数据是不是 KV 缓存。这些都是 Store 或上层框架的职责。
核心入口:
mooncake-transfer-engine/include/transfer_engine.h
mooncake-transfer-engine/include/transport/transport.h
mooncake-transfer-engine/src/transfer_engine_impl.cpp
mooncake-transfer-engine/src/multi_transport.cpp
layer view
Transfer Engine 只处理远端可寻址内存上的字节传输
Store 把对象和副本信息转换成 Segment、偏移量与长度;Transfer Engine 再把这些字段交给具体传输后端。
公开 API
调用者看到的统一入口
寻址模型
远端位置不是裸指针
本地内存
本地缓冲区必须能被传输层使用
批量执行
一批请求统一提交和轮询
TransferEngine 提供哪些接口
Transfer Engine 的公开接口可以分成几类:
init / freeEngine
installTransport / uninstallTransport / getTransport
openSegment / closeSegment / removeLocalSegment
registerLocalMemory / unregisterLocalMemory
allocateBatchID / freeBatchID
submitTransfer
getTransferStatus / getBatchTransferStatus
这些 API 说明它不是 KV 存储,而是负责内存注册、Segment 发现和批量传输任务。
Segment 表示远端可寻址空间
传输任务不能只给出一个“远端指针”。跨进程或跨机器时,本地进程不能直接使用远端虚拟地址。Transfer Engine 会先通过 openSegment(segment_name) 得到 SegmentHandle。
Store 侧的 Segment 元数据会告诉 Client:
segment id
segment name
base
size
te_endpoint
protocol
Transfer Engine 侧拿到 Segment 后,传输任务才能表达:
target_id
target_offset
length
也就是说,Store 的副本描述最终会转换为 Transfer Engine 所需的 Segment、偏移量和长度。
registerLocalMemory 是传输数据的前置条件
许多传输后端不能直接使用任意一段由 malloc 分配的内存做高速传输。RDMA、GPU P2P、NVLink 和 EFA 等路径通常需要固定内存页、注册内存区域、生成访问键或建立映射。
因此 Transfer Engine 暴露:
registerLocalMemory(addr, length, location, remote_accessible, update_metadata)
unregisterLocalMemory(addr)
registerLocalMemoryBatch(...)
这一步的意义是告诉 Transfer Engine:这段本地缓冲区可以参与传输。
SGLang 接入 Mooncake Store 时,Mooncake 后端会注册主机 KV 池。之后 batch_get_into 和 batch_put_from 才能把主机 KV 缓存页指针直接交给 Store 和 Transfer Engine,而不需要把数据复制成 Python 字节串。
TransferRequest 描述一次基本传输
Transfer Engine 的核心请求可以简化为:
TransferRequest
opcode: READ | WRITE
source: 本地缓冲区地址
target_id: 远端 Segment ID
target_offset: 远端 Segment 内的偏移量
length: 字节数
READ 和 WRITE 的区别在于数据方向:
READ:
远端 Segment -> 本地 source 缓冲区
WRITE:
本地 source 缓冲区 -> 远端 Segment
call path
同一个 TransferRequest,方向由 opcode 决定
`source` 在 Transfer Engine 中表示本地缓冲区地址。READ 时它是目的地;WRITE 时它是来源。
- 1
本地缓冲区
TransferRequest
WRITE source=addr
本地切片或主机 KV 页作为数据来源
- 2
TransferRequest
远端 Segment
target_id + target_offset + length
把数据写到副本对应的位置
- 3
远端 Segment
TransferRequest
READ target_id + target_offset
从远端 Segment 读取数据
- 4
Transfer Engine
本地缓冲区
填充 source=addr
READ 的结果写回本地缓冲区
字段名 source 需要按 Transfer Engine 的语义理解:它是本地缓冲区地址,具体方向由操作码决定。
BatchID 与批量任务
Transfer Engine 不鼓励逐个同步传输小对象,而是使用 BatchID 表达一组传输请求:
BatchID id = allocateBatchID(batch_size)
submitTransfer(id, requests)
getBatchTransferStatus(id, status)
freeBatchID(id)
这对 KV 缓存很重要。一个前缀可能有大量缓存页,每个缓存页又可能拆成 K/V 对象。如果每个对象都独立提交,提交和轮询开销会非常高。
BatchTransfer 的目标是把许多小传输组织成一批,让传输层统一调度和查询状态。
TransferStatus 只表示传输状态
Transfer Engine 的状态只描述数据传输:
WAITING
PENDING
COMPLETED
TIMEOUT
FAILED
CANCELED
这些状态只说明传输任务是否完成,不说明 Store 对象是否可读。
例如在 Put 路径中,WRITE 传输成功以后,Store 仍然需要通过 PutEnd 把副本提交为 COMPLETE。反过来,在 Get 路径中,即使 Master 返回了 COMPLETE 副本,只要 READ 传输失败,上层仍然不能使用数据。
因此要区分:
TransferStatus:
数据是否传输完成
ReplicaStatus:
对象副本是否可读
Transfer Engine 在 Store Put/Get 中的位置
Put 时:
Store 副本
-> TransferSubmitter
-> TransferRequest(WRITE)
-> TransferEngine.submitTransfer
-> 传输后端
Get 时:
Store 副本
-> TransferSubmitter
-> TransferRequest(READ)
-> TransferEngine.submitTransfer
-> 填充本地切片
Store 负责对象、副本和租约;Transfer Engine 负责数据搬运。这个边界不应该混淆。
为什么这层要独立出来
如果 Store 自己直接实现 RDMA/TCP/NVLink/EFA,每增加一种后端都会影响对象语义层。
Transfer Engine 独立出来以后,Store 只需要表达:
把切片写入副本
从副本读入切片
底层到底采用哪种传输方式,由 Transfer Engine 和 MultiTransport 处理。
这让 Mooncake 能同时支持多种部署形态:本地开发可以使用 TCP,生产环境可能使用 RDMA 或 EFA,同机多卡可能使用 NVLink,异构硬件还可以接入其他后端。
和 Store 语义保持距离
Transfer Engine 的关键边界是:它只知道传输任务,不知道对象生命周期。TransferStatus.COMPLETED 表示字节传输完成;ReplicaStatus.COMPLETE 表示 Store 认为这个对象副本可以读取。写入路径中,前者成功后还需要 PutEnd;读取路径中,后者存在后还需要 READ 成功。
这层独立性是 Mooncake 能扩展多种传输方式的原因。Store 不需要知道 RDMA 内存区域、NVLink IPC 或 TCP 连接怎样管理;Transfer Engine 也不需要知道对象键、租约,以及 K/V 对象是否同属于一个逻辑页。两边只通过 Segment、偏移、长度和本地缓冲区地址交接。
读源码时如果觉得概念混在了一起,可以先问一句:眼前的状态是在描述“数据是否已经传输完成”,还是在描述“对象副本是否对读取方可见”。这两个问题分属不同层次。