CloudMatrix384 LLM Serving
一句话先懂
如果把大模型推理看成一家爆单餐厅,CloudMatrix384 的思路不是让一位厨师跑得飞快,而是:
- 把长提示词的预处理、逐 token 生成、缓存保管拆成不同工位。
- 让每个 token 去找自己需要的 MoE 专家,而不是把所有专家复制到每张卡。
- 把矩阵计算、向量整理和数据搬运交错起来,少让硬件空等。
- 把可复用的 KV Cache 放进共享内存池,下次只计算新来的后缀。
这里的关键不是某一个神奇算子,而是把系统里不同形状的等待,交给不同资源处理。
先把地图摊开
论文中的 CloudMatrix384 包含 384 个 Ascend 910 NPU package 和 192 个鲲鹏 CPU。一个 package 内含两个 die,论文又常以 die 作为通信 rank,因此你会同时看到“160 个 NPU package”和“320 路 EP”这样的数字。
系统也不是“所有数据都走同一根线”。论文描述的当前实现仍区分:
- UB(UnifiedBus):NPU 间及 NPU 到共享内存池的高带宽、低时延通路。
- RDMA 网络:预填集群向解码集群传完整 KV Cache 时使用。
- VPC 网络:通用网络路径,也是论文缓存实验中的对照路径。
论文实际性能评估使用其中 256 个 NPU:96 个用于预填,160 个用于解码,并使用 32 个节点的 CPU DRAM。模型是 DeepSeek-R1 671B 的 INT8 版本。所以“CM384 的系统设计”与“256 NPU 的实验切片”也不能混为一谈。
PDC:三间工坊
PDC 是 Prefill/Decode/Caching Disaggregation(预填、解码、缓存解耦)。
- Prefill 一次读完整段提示词,计算首 token,并生成初始 KV Cache,计算更密集。
- Decode 每轮只生成一个或少数 token,却要不断读取历史 KV Cache,更吃内存带宽与低时延。
- Caching 用 CPU DRAM 汇聚上下文缓存与模型缓存,为多个 NPU 提供共享容量。
如果强迫同一种实例同时兼顾三者,就像让备菜师一边切一百斤菜,一边每秒端一只盘子,还要自己看守仓库。PDC 允许三类资源按流量分别扩缩。
运行过程
下面是语义伪代码,用来说明对象与完成条件,不是论文公开 API:
1 | def serve_request(request): |
论文给出的典型布局是:
- 预填实例用 16 个 NPU package,也就是 32 个 die/rank,做 EP32。
- 解码实例用 160 个 NPU package,也就是 320 个 die/rank,做 EP320。
- 预填完成后,后台线程先在解码侧分配目标 KV 地址,再通过 RDMA 搬一次完整 KV;解码的 MoE 高频通信则尽量留在 UB。
代价与边界
PDC 没有消灭 KV Cache,而是改变它的所有权和搬运时机。新增代价包括目标地址预留、RDMA 传输、完成通知、容量调度和故障恢复。只有当分池后的利用率收益,大于跨池交接成本时,解耦才值得。
EP320:token 去找专家
DeepSeek-R1 的 MoE(Mixture of Experts,专家混合)层不会让每个 token 经过全部专家。门控网络为每个 token 选择 topK=8 个路由专家。CloudMatrix-Infer 把专家铺到 320 个 rank 上,让 token 主动“寄快递”到专家所在处。
困难是:一个 MoE 层通常要经历发路由信息、发 token、做专家 FFN、把结果寄回。小批量解码时,每个包裹很小,通信启动和同步反而可能比计算更显眼。
论文的 LEP(Large-scale Expert Parallelism,大规模专家并行)用两个融合算子解决:
- FusedDispatch:尽早把 BF16 hidden 量化为 INT8 加 scale,附上来源信息,直接写入目标 rank 的静态缓冲区。
- FusedCombine:专家算完后按来源信息写回,等待贡献齐全,再反量化并按门控权重求和。
运行过程
1 | def fused_moe(hidden, gate, topology, buffers): |
图里最值得盯住的是两件事:token 被量化后搬走,scale 与来源元数据必须一起活着;返回结果必须等八路贡献齐全才能相加。
缓冲区公式
静态缓冲区避免每轮临时分配,但必须按最坏情况预留:
$$
\text{max_tokens}
\text{local_batch}
\times
\min(\text{topK}, \text{experts_per_die})
$$
$$
\text{buffer_size}
\text{rank_num}
\times
\text{max_tokens}
\times
\text{msg_size}
$$
在论文给出的 320 rank、local batch 96、每 die 一个专家配置下,dispatch 缓冲区约 225 MB,combine 缓冲区约 420 MB,合计约 645 MB/die。双缓冲还要避免 combine 覆盖仍在使用的 dispatch 数据。
微批流水:少让硬件等待
Ascend NPU 中,AIC 更擅长矩阵计算,AIV 更擅长向量整理和部分通信控制,SDMA 负责大块数据搬运。若严格串行执行,常出现“矩阵单元算完了,等通信;通信单元忙完了,又等下一次矩阵”。
CloudMatrix-Infer 把 batch 切成 microbatch(微批),让两个微批在不同阶段交错。论文的解码示例中,Attention 路径与 MoE 路径各约 600 μs,因此有机会像接力一样重叠。
运行过程
1 | def run_layer_with_two_streams(microbatches, attention_stream, moe_stream): |
预填阶段的搭配略不同:AIC 主跑 Attention/MLP,AIV 跑 Dispatch/Combine 的计算部分,SDMA 做大块 all-to-all;两个微批再次交错。长序列的 MLA 还采用 SP-TP-SP:先按序列切分,再按头做张量并行,最后切回序列并行,以两次集合通信换更均匀的负载。
适用边界
微批不是越小越好:
- 太大:可重叠的窗口少,尾部等待长。
- 太小:算子启动、同步和碎片化开销上升。
- KV 长度变化:Attention 时间会随上下文增长,固定切分可能失衡。
- 内存压力:同时活着的微批更多,中间张量和 workspace 的峰值可能上升。
论文同系统消融中,解码吞吐提升约 **5.8%–9.4%**,预填在所测设置中提升约 **23%–31%**。这些数字说明“重叠在该配置有效”,不保证迁移到任意模型和序列长度仍有相同比例。
EMS:共享 KV 图书馆
EMS(Elastic Memory Storage,弹性内存存储)把多个节点的 CPU DRAM 汇成共享池,并用 SSD 作为更冷的层级。上下文缓存按 128–512 token 切块,用“前缀哈希 + 当前 token 块”形成链式身份。
想象很多人都问:“请总结同一份 4000 字报告,但关注点不同。”如果前 3500 字相同,就不必每次重算。缓存系统先找到最长的相同前缀,只计算新后缀。
运行过程
1 | def prefill_with_ems(tokens, block_size, ems, prefill_engine): |
命中率边界
论文在 4K 输入、总 batch 为每 NPU 16K token 的设置下报告:
- 上下文复用率达到 90% 时,相比不使用 EMS,吞吐达到 2.28×。
- 通过 UB 访问缓存,相比 VPC 路径最高达到 1.52×。
但复用率为零时,缓存不能替你省计算,还会多一次查询。并且 DeepSeek-R1 的推理链包含生成的 reasoning token 与位置变化,论文通常不把 decode 新生成的 KV 当作跨请求上下文缓存。EMS 最适合稳定、重复、块对齐的长前缀,不是所有对话的万能记忆。
三种最后一公里
四个主机制之外,论文还叠加了三类优化。它们更像“把剩余缝隙再挤一遍”,不要和前面的系统分工混成一个概念。本节只帮助你辨认作用方向与证据边界,不把它们冒充成量化、MLA 或推测解码的完整实现教程。
INT8:少搬一些
论文采用训练后、分层混合精度:计算密集的矩阵乘尽量用 INT8,归一化、门控等敏感位置保留 BF16/FP32;权重使用 per-channel scale,激活使用 per-token scale,并处理离群值。
这里有两个不同层次的 INT8:
- 模型量化减少选定权重和激活的计算/存储开销。
- Dispatch 提前量化专门减少 MoE 跨 rank 消息,从 BF16 hidden 变为 INT8 加 scale。
论文在 16 个基准上报告总体可比,但比较中可能存在 API、采样参数和评分器差异,因此准确说法是“在作者设置中总体保持”,不是“INT8 永不掉点”。
MLA 融合:少落几次地
MLA(Multi-head Latent Attention,多头潜在注意力)相关路径把 RMSNorm、QKV、RoPE 合进 MLAProlog,把 FlashAttention 与拼接/切片合并,并让 KV Cache 直接保持更适合 NPU 的 NZ 布局。
它减少中间张量写回和布局转换,但融合算子仍需要 workspace、寄存器与片上缓存;输入形状变化也会影响 tiling。少一次中间落地,不等于峰值显存按同样比例下降。
MTP:一次多猜一点
MTP(Multi-Token Prediction,多 token 预测)让一次迭代猜多个后续 token,再验证可接受的前缀。论文假设一个推测 token 的接受率为 70%,平均每轮接受约 1.7 个 token。
吞吐收益取决于接受率和 batch;验证分支又增加了本轮计算。论文报告的提升范围约 **6%–49%**,同时 batch 96 的单层迭代时延增加约 **44%**。所以 MTP 的核心是“用更多单轮工作换更少迭代轮数”,不是单轮更快。
数字应该怎样读
先认识三个指标:
- TTFT(Time To First Token):从请求到首 token,主要看预填。
- TPOT(Time Per Output Token):后续每个输出 token 的间隔,主要看解码。
- tokens/s/NPU:每个 NPU 的吞吐,仍受 batch、精度、缓存长度和软件实现影响。
论文 Table 2 的默认预填结果是 5655 tokens/s/NPU;6688 对应的是 Perfect EPLB,也就是理想化专家负载均衡,不应写成默认实测。
Table 3 中,CM384 解码行是 1943 tokens/s/NPU、49.4 ms TPOT、batch 96、4K KV Cache。同表的 H800/H100 数据来自博客、profile 或模拟,batch 和软件也不同。tokens/s/TFLOPS 提供了一种归一化视角,但仍不是总成本、能耗或生产成熟度的完整比较。
内存账本
一篇系统文章最容易制造的错觉,是“某个对象搬走了,所以内存消失了”。更稳妥的峰值账本是:
$$
M_{\text{peak}}
M_{\text{model state}}
+
M_{\text{saved activations}}
+
M_{\text{operator workspace}}
+
M_{\text{communication buffers}}
+
M_{\text{live I/O}}
+
M_{\text{allocator reserved unused}}
+
M_{\text{runtime margin}}
$$
在推理中,saved activations 通常比训练少,但其他项仍然存在:
- PDC:把部分 KV 与模型缓存从 NPU HBM 移到 CPU DRAM;增加传输目标、完成状态与在途数据。
- LEP:减少每 rank 的专家权重压力;增加约束于配置的 dispatch/combine 静态缓冲。
- 微批:提高硬件重叠;可能让更多中间张量和 workspace 同时活着。
- EMS:扩大共享缓存容量;增加 DRAM/SSD 层级、哈希元数据和注册内存。
- INT8:减少选定权重与消息;增加 scale、量化/反量化临时对象和误差边界。
因此,正确的结论是内存被重排、分层和设上界,而不是凭空消失。
小白检查清单
读完后,不妨试着回答:
- 为什么 prefill 和 decode 的最佳硬件配比不同?
- PDC 的 KV Cache 在什么时候、从哪里、搬到哪里?
- EP320 为什么能省专家权重复制,却要付通信缓冲区?
- 微批流水提升的是单算子速度,还是系统重叠率?
- EMS 的 2.28× 为什么必须同时写上“90% 复用率”和测试条件?
- Table 3 为什么不能直接变成 Ascend、H800、H100 的排行榜?
如果这些问题能用自己的话讲清,你已经抓住了这篇论文最值得迁移到其他系统的部分。
总结
CloudMatrix384 的故事可以压缩成一句话:先承认大模型推理不是一种工作,再为每种工作安排合适的资源、通路与状态所有权。
- PDC 解决不同阶段的资源错配。
- LEP 解决超大 MoE 专家如何分布与低时延交换。
- 微批流水解决异构计算单元互相等待。
- EMS 解决长前缀重复计算与 NPU HBM 容量。
- INT8、算子融合与 MTP 再分别压缩数据、减少落地和减少迭代轮数。
真正可复用的不是某个数字,而是这套对象—路径—完成条件—峰值账本—证据边界的分析方法。
参考资料
- Huawei & SiliconFlow, Serving Large Language Models on Huawei CloudMatrix384, arXiv
2506.12708v3, 2025. - 想飞的石头,《Serving Large Language Models on Huawei CloudMatrix384》学习笔记,2025-06-22.