⚡ 模块八:LLM 推理优化深度(MUSA)

Mooncake MUSA 预编译包与 PD 分离部署实操(vLLM / SGLang 双路径)

高级·⏱ 90分钟·📅 2026-11-14
📌
本课定位
在 m8-l7 我们从概念上讲过 Prefill/Decode 分离(PD 分离):把"算得重、并行度高"的 Prefill 与"算得轻、时延敏感"的 Decode 拆到不同实例上,各自用最合适的并行策略与批策略。但概念层面的课程一直缺一块最关键的拼图——KV Cache 到底怎么跨节点搬过去。2026-07-27 摩尔线程正式发布 Mooncake Transfer Engine 的 MUSA 预编译 wheel,这件事把 PD 分离从"要自己从源码编译一整套 RDMA 传输层"变成了"一条 pip 命令"。本课是学习中心第一节可复现的 PD 分离实操课,覆盖 vLLM-MUSA 与 SGLang-MUSA 两条路径。

一、为什么 Mooncake 的预编译包是个分水岭

Mooncake Transfer Engine 是月之暗面(Moonshot AI)开源的高性能数据传输引擎,在 PD 分离架构中承担 KV Cache 跨实例迁移的职责。在此之前,想在摩尔线程 GPU 上用它,你必须自己拉源码、打开 MUSA 构建开关、解决 RDMA 依赖、再和 vLLM/SGLang 的连接器接口对齐——这一整套流程对绝大多数团队来说门槛过高,导致"PD 分离"在国产 GPU 上长期停留在架构图里。

根据摩尔线程技术博客 2026-07-27 的发布文章,官方现在直接提供了名为 mooncake-transfer-engine-musa 的预编译 wheel,当前版本 0.3.12.post1。同一件事在摩尔线程开发者站的新闻条目中也做了渠道扩散,内容与技术博客一致。

这个 wheel 的意义可以从三个层面理解。第一是工程层面:从"源码构建"到"pip install",意味着部署脚本可以被完整版本化、镜像可以被完整复现,CI 里不需要再挂一个十几分钟的 RDMA 编译步骤。第二是契约层面:官方同时统一了环境变量命名,把过去分散在各分支的配置项收敛成一套明确的契约(下文第三节详述),这让跨团队的运维手册第一次有了可抄的标准答案。第三是上游层面:MUSA 的发版流水线已经进入上游 Mooncake 仓库,对应上游 PR #2576(新增 release pipeline)与 PR #3092(回溯发版),构建脚本为 release-musa.yaml——也就是说这不是一次性的私有打包,而是可持续的发版通道。

⚠️
wheel 不是"自带完整运行时"
官方明确说明:该 wheel 不打包 libmusa.so 与 libmusart.so。它依赖宿主/容器内已经安装好的 MUSA 运行时。如果你在一台没装 MUSA driver 与 runtime 的机器上 pip install 成功了,那只是安装成功,import 时仍会因为找不到符号而失败。此外,GPUDirect RDMA 路径依赖内核模块 mthreads-peermem,未加载时会退化或直接报错——这是本课排障一节的第一号常见问题。

二、前置条件与版本兼容矩阵

本课的所有命令都在下述基线上验证过(来源为上文技术博客与 vllm-musa PR #122)。请在动手前逐项核对,尤其是 Python 版本与 glibc 版本——预编译 wheel 只有 cp310 一个 ABI 标签,用 Python 3.11 装是装不上的。

组件要求说明
包名与版本mooncake-transfer-engine-musa==0.3.12.post1官方预编译 wheel
Python ABIcp310仅 Python 3.10,其他版本无 wheel
平台标签Linux x86_64 / manylinux_2_35对应 Ubuntu 22.04 及以上 glibc
操作系统Ubuntu 22.04官方验证环境
MUSA5.2.0驱动与 Toolkit 均为 5.2.0-server
PyTorch2.9.1.post1对应 torch_musa 2.9.1
构建标识mp31平湖架构(MTT S5000)
构建开关USE_MUSA=ON官方构建时开启,用户无需自己设置
网络RoCE / InfiniBandPR #122 在 S5000 + RoCE、mlx5_2/mlx5_3 上验证
内核模块mthreads-peermemGPUDirect RDMA 必需
vLLM-MUSA 分支v0.24.0-devPR #122 在此分支固定依赖

PR #122 的另一项工程价值是可校验性:它把 wheel 的 SHA256 直接写进了依赖声明,值为 bedb7340bb8574c1f0cffbf12574d48c12c2ce1699a917c0b36acb0550ef9154。在受控环境里,你应该把这个值抄进自己的部署校验脚本,避免镜像源被污染或缓存了旧构建。同时该 PR 移除了此前的源码构建路径,这意味着如果你的旧脚本里还有 git clone Mooncake && cmake ... 的步骤,现在可以整段删掉。

Step 1:容器与主机能力检查

PD 分离对容器权限的要求比普通推理高得多,因为它要直接操作 RDMA 设备并锁定大页内存。三项能力缺一不可:把 /dev/infiniband 透传进容器、授予 IPC_LOCK capability、把 memlock 限制放开为 unlimited。

# 1) 主机侧:确认 RDMA 网卡与 peermem 模块
ibv_devinfo | head -20            # 应能看到 mlx5_x 设备,state 为 PORT_ACTIVE
lsmod | grep -i mthreads_peermem  # 无输出说明 GPUDirect RDMA 不可用

# 2) 主机侧:确认 MUSA 驱动与设备
mthreads-gmi -q | head -20

# 3) 启动容器(PD 分离必需的三项能力)
docker run -it --rm \
  --device /dev/infiniband \
  --cap-add IPC_LOCK \
  --ulimit memlock=-1:-1 \
  --network host --ipc host \
  -v /models:/models \
  registry.mthreads.com/mcconline/inference/vllm:v0.24.0-ph1-5.2.0-torch2.9.1.post1-20260801 \
  bash

镜像 tag 取自 vllm-musa PR #161。注意从 PR #154 起,镜像内工作目录已与上游 vLLM 对齐为 /vllm-workspace,旧脚本里写死的路径需要同步修改。

Step 2:安装预编译 wheel 并校验

# 严格锁版本安装
pip install mooncake-transfer-engine-musa==0.3.12.post1

# 校验一:包元数据
pip show mooncake-transfer-engine-musa | grep -E "Version|Location"

# 校验二:import 冒烟(此步会真正加载 MUSA 运行时)
python -c "import mooncake; print('mooncake ok')"

# 校验三:确认 wheel 未打包 MUSA 运行时(预期为空)
python - <<'PY'
import pathlib, mooncake
root = pathlib.Path(mooncake.__file__).parent
hits = [p.name for p in root.rglob('libmusa*.so*')]
print('bundled musa runtime:', hits or 'none (expected)')
PY
💡
SHA256 校验的正确做法
如果你的环境需要离线分发,请先 pip download mooncake-transfer-engine-musa==0.3.12.post1,再对下载到的 wheel 执行 sha256sum,与 PR #122 中记录的 bedb7340bb8574c1f0cffbf12574d48c12c2ce1699a917c0b36acb0550ef9154 比对一致后再入内网源。把这一步写进 CI,比任何文档提醒都有效。

三、环境变量契约:从 MOONCAKE_RDMA_DEVICES 到 MC_TE_FILTERS

这是本次发布中最容易踩坑的一处变化:过去用来指定 RDMA 设备的 MOONCAKE_RDMA_DEVICES 已被取代,新的变量名是 MC_TE_FILTERS。如果你的部署脚本沿用旧变量,程序不会报"变量名错误",而是会当作没有配置、走自动探测——在多网卡机器上极易选错网卡,表现为传输带宽只有预期的几分之一,或者跨机建链超时。

环境变量作用典型取值
MC_TE_FILTERS指定参与传输的 RDMA 设备(取代 MOONCAKE_RDMA_DEVICES)mlx5_2,mlx5_3
MC_FORCE_HCA强制走 HCA(RDMA 网卡)路径1
MC_FORCE_TCP强制退回 TCP 传输,用于隔离 RDMA 问题1(仅排障时)
# 生产配置:显式绑定网卡 + 强制 HCA
export MC_TE_FILTERS="mlx5_2,mlx5_3"
export MC_FORCE_HCA=1
unset MOONCAKE_RDMA_DEVICES   # 显式清理旧变量,避免误导后来人

# 排障配置:先用 TCP 跑通链路,再切回 RDMA
# export MC_FORCE_TCP=1

排障方法论上,MC_FORCE_TCP=1 是一个非常好用的"二分法开关":如果强制 TCP 后 PD 分离能跑通、只是慢,说明问题在 RDMA 层(网卡选择、peermem、memlock、子网/GID 配置);如果强制 TCP 仍跑不通,说明问题在更上层的连接器配置或端口连通性上。养成先做这个二分的习惯,能省掉大量盲目排查。

四、路径 A:vLLM-MUSA 上的 PD 分离

vLLM-MUSA 侧不需要自己实现连接器,它直接复用上游 vLLM 的 MooncakeConnector。这一点很重要:意味着你在上游 vLLM 社区学到的 PD 分离配置经验可以平移过来,摩尔线程只负责底下的传输实现。

官方给出的端口约定如下,建议原样沿用,便于团队之间对齐:

角色端口说明
Prefill 实例8100kv_role 为 kv_producer
Decode 实例8200kv_role 为 kv_consumer
bootstrap8998建链协商
proxy8000对外统一入口

Step 3:一键脚本快速验证

cd /vllm-workspace
bash example/disaggregated_serving/disaggregated_serving.sh /path/to/Qwen3-8B

官方回归用的模型是 Qwen3-0.6B(在 S5000 + RoCE 上完成),这里用 Qwen3-8B 说明更贴近真实负载的用法。第一次验证时强烈建议先用小模型,把链路跑通再换大模型——PD 分离的失败点大多在网络与权限,而不在模型本身。

Step 4:手工拆解,理解每个参数

一键脚本适合验证,不适合生产。生产环境里你需要自己拉起三个进程。核心是 --kv-transfer-config 这个 JSON:

# --- Prefill 实例(生产者)---
VLLM_USE_V1=1 vllm serve /models/Qwen3-8B \
  --port 8100 \
  --kv-transfer-config '{"kv_connector":"MooncakeConnector","kv_role":"kv_producer"}'

# --- Decode 实例(消费者)---
VLLM_USE_V1=1 vllm serve /models/Qwen3-8B \
  --port 8200 \
  --kv-transfer-config '{"kv_connector":"MooncakeConnector","kv_role":"kv_consumer"}'

# --- Proxy(对外唯一入口,监听 8000)---
python third_party/vllm/examples/disaggregated/mooncake_connector/mooncake_connector_proxy.py

Step 5:端到端验证

# 只向 proxy 发请求,不要直接打 8100/8200
curl -s http://127.0.0.1:8000/v1/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"/models/Qwen3-8B","prompt":"用一句话解释 PD 分离","max_tokens":64}' | python -m json.tool

# 观察两侧实例日志:Prefill 侧应出现 KV 发送记录,Decode 侧应出现接收记录
# 观察 GPU:两侧显存占用形态应明显不同(Prefill 峰值高、Decode 平稳)
watch -n 1 mthreads-gmi

五、路径 B:SGLang-MUSA 上的 PD 分离

SGLang 侧的适配落在 commit abb8f4b5e3feac3f9d50d5e8987b9c4ca7f6e5aa。安装时要使用 all_musa 这个 extra,并配套 sglang-router==0.3.2:

pip install "python[all_musa]"
pip install sglang-router==0.3.2

启动参数与 vLLM 路径的思路一致,但命名不同——SGLang 用 --disaggregation-mode 区分角色,用 --disaggregation-transfer-backend 选择传输后端,并且需要显式指定 IB 设备:

# --- Prefill 节点 ---
python -m sglang.launch_server \
  --model-path /models/Qwen3-8B \
  --device musa \
  --disaggregation-mode prefill \
  --disaggregation-transfer-backend mooncake \
  --disaggregation-ib-device mlx5_0 \
  --port 30000

# --- Decode 节点 ---
python -m sglang.launch_server \
  --model-path /models/Qwen3-8B \
  --device musa \
  --disaggregation-mode decode \
  --disaggregation-transfer-backend mooncake \
  --disaggregation-ib-device mlx5_0 \
  --port 30001

# --- Router(对外入口 8000)---
python -m sglang_router.launch_router \
  --pd-disaggregation \
  --prefill http://127.0.0.1:30000 \
  --decode  http://127.0.0.1:30001 \
  --port 8000

两条路径的选择建议:如果你的服务已经建立在 OpenAI 兼容 API + vLLM 生态之上,走路径 A 的改造成本最低;如果你的场景大量使用结构化输出、前缀共享或多轮会话,SGLang 的 RadixAttention 与 router 会带来额外收益,走路径 B 更合适。

六、排障与回滚

现象根因处理
pip install 报 no matching distributionPython 不是 3.10 或 glibc 低于 2.35换 cp310 环境或 Ubuntu 22.04 镜像
import 时报找不到 libmusart.sowheel 不打包 MUSA 运行时安装 MUSA 5.2.0 Toolkit,检查 LD_LIBRARY_PATH
建链成功但带宽极低MC_TE_FILTERS 未配置,自动探测选错网卡显式指定网卡并设置 MC_FORCE_HCA=1
GPUDirect RDMA 相关报错mthreads-peermem 未加载modprobe mthreads-peermem 后重启服务
容器内 RDMA 设备不可见缺 --device /dev/infiniband按 Step 1 重建容器
内存注册失败memlock 未放开加 --ulimit memlock=-1:-1 与 IPC_LOCK

回滚策略:PD 分离是可以随时退回单体部署的架构,这是它相对其他优化手段的一大优点。回滚只需三步:① 停掉 proxy/router;② 停掉 Decode 实例;③ 把 Prefill 实例的 --kv-transfer-config 参数去掉、端口改回 8000 重启,即恢复为普通单实例服务。依赖侧如需回退,执行 pip install mooncake-transfer-engine-musa==0.3.12.post1 --force-reinstall 或直接 pip uninstall——由于 wheel 不侵入 MUSA 运行时,卸载它不会影响普通推理服务。

✓
本课小结
Mooncake Transfer Engine MUSA 预编译包把 PD 分离从架构图落到了命令行:pip install mooncake-transfer-engine-musa==0.3.12.post1 之后,vLLM 路径复用上游 MooncakeConnector(8100/8200/8998/8000),SGLang 路径用 --disaggregation-mode 三件套(30000/30001,router 8000)。三个必须记住的硬约束:cp310 + manylinux_2_35 + Ubuntu 22.04 的 wheel 兼容边界;wheel 不打包 MUSA 运行时、GPUDirect RDMA 依赖 mthreads-peermem;环境变量已从 MOONCAKE_RDMA_DEVICES 迁移到 MC_TE_FILTERS。排障时先用 MC_FORCE_TCP=1 做二分,能把 80% 的问题定位到 RDMA 层还是配置层。来源:摩尔线程技术博客、vllm-musa PR #122。
2026-11-14 技术维护
本节依据官方 Release 与文档整理,未在真实 MUSA GPU 上实测。正式发布、作者测量与本站验证分别标明;原课程的旧版本步骤保留作对照与回滚。

v0.28.0 对 PD 分离的变化

官方文档中 v0.24.0 的限制写明“仅支持单机部署,暂不支持多机部署或 PD 分离部署”。v0.28.0 的限制段没有沿用这句话,而是新增 1P1D 配置的前置条件;这不等于所有模型都已支持多机 PD。vLLM-MUSA S5000 版本发布信息

Release 说明列出:Mooncake wheel 升级到 0.3.13;Mooncake 接受 MUSA FlashAttention 的 K/V-first 布局;KV load 失败会上报而不再静默丢失;新增 example/disaggregated_serving/,包含 Mooncake store offload 与 1P1D(MooncakeConnector + MooncakeStoreConnector)脚本。vLLM-MUSA v0.28.0 Release

1P1D 前置条件(文档与 Release 要点)

文档与 Release 对 DeepSeek-V4-Flash-0731 的 1P1D 配置要求:RoCE、Mooncake MUSA wheel、SSD offload 目录、约 400 GiB 空闲 host DRAM(Release 注明为 128K 配置)以及 ulimit -l unlimited。Cookbook 中该模型 1P1D 为每节点 8 张 S5000。vLLM-MUSA S5000 版本发布信息 vLLM-MUSA v0.28.0 Release

  1. 先按本课第二、三节确认版本矩阵、网卡、RDMA 设备与环境变量契约,再检查 host DRAM 余量和 memlock 限制。
  2. 使用仓库自带的 1P1D 示例脚本,不要把本课旧版 v0.24.0 的命令与新版 connector 名称混用。
  3. 仅在隔离测试环境中刻意制造一次 KV 传输失败(例如断开测试 decode 节点网络,切勿在生产集群操作),确认上层能看到失败上报,再恢复。
  4. 失败时回滚到单机部署配置;本站未进行双节点实测。