Mooncake File vs Block Device

导言

我最开始想确认的是一个很具体的问题:Mooncake Classic TE 和 TENT 打开的究竟都是文件系统普通文件,还是也能把 /dev/nvme0n1 这样的 SSD 裸块设备交给 GDS?源码里两边都会调用 open(path, O_DIRECT),NVIDIA cuFile 又确实接受 device fd,看起来答案应该是“可以”。继续向上追到 Segment 层后,结论却发生了分叉。

这篇文章把这条调用链从头串起来:先解释普通文件、块设备、S_ISREG 与 S_ISBLK,再看 GDS 提供了什么 API、Mooncake 实际用了什么,最后落到 cuFileBatchIOSubmit 的同一组参数为什么在两个场景里具有不同含义。核心判断是:GDS 统一了 I/O 接口,却没有替 Mooncake 补上块设备的容量、对齐、越界和独占语义。

Read more

Mooncake Classic vs TENT Engine

导言

看到“应用必须持有 Transport*”时,我真正卡住的是:持有到底是什么意思?为什么直接保存一个后端指针就能工作,统一的 TransferEngine 反而走不通?

把这个词拆开后,Classic 与 TENT 的差异就不再只是两套接口。Classic 的公共 Batch 先于后端选择而创建,后端私有状态缺少稳定的安放位置;TENT 则在选定后端后,为每个 transport 创建独立 SubBatch,再由统一运行时协调提交、状态与回收。

因此,判断一个 Engine 是否容易扩展多个后端,不能只数有多少个 Transport 子类。真正要问的是:后端的私有状态放在哪里,由谁创建,又由谁保证它完成整个异步生命周期。

Read more

Mooncake Classic NVMeoF Transport

导言

在分析 Mooncake 的 NDS 接入位置时,经典 NVMeoFTransport 很容易被误认为 TENT GdsTransport 的前一版:二者都注册 buffer 和文件 handle,都使用 cuFile Batch API,也都维护异步完成事件。

但这条旧路径真正特殊的地方不在 cuFile,而在 Batch 所有权。可运行的调用必须直接持有 Transport*,并始终走 xport->allocateBatchID → xport->submitTransfer → xport->getTransferStatus → xport->freeBatchID。一旦换成 engine->allocateBatchID → engine->submitTransfer,批次便由 MultiTransport 创建,NVMeoFTransport 无法附加私有 descriptor,最终返回 NotImplemented。

本文把这条旧路径单独展开:先给出从 NVMe-oF 挂载到专用测试的 SOP,再画出可运行路径与断路分支,最后按执行顺序逐句解释 Batch 分配、请求切片、cuFile 提交、完成事件聚合与资源回收。

Read more

Mooncake Codebase Architecture

导言

上一篇文章从 FAST’25 论文出发,解释了 P/D 解耦、分布式 KV Cache 与调度机制。论文读懂以后,打开代码仓却很容易再次迷路:Connector、Mooncake Store、Transfer Engine、TENT 看起来像四个并列组件,实际却跨越 vLLM 与 Mooncake 两个仓库,并分别承担框架适配、对象管理、字节搬运和新传输内核。

本文固定在 Mooncake 6a00c353 与 vLLM 5bbc58c0,从仓库结构、请求流、时序和关键类关系重新组织这些概念,最后给出一套可重复的源码走读与开发 SOP。

Read more