Kimi-K3 原始 MXFP4 权重512K 长上下文生产部署:双机 16 卡 TP8×PP2 与 CUDA Graph 调优
大模型推理基础设施实战系列 · 第 4 篇
硬件:双机 16×H20,机内 NVLink/NVSwitch,机间 RoCE。
1. 背景与问题:先把显存账算对
目标是在两台各 8×H20 的服务器上运行 Kimi-K3 原始 MXFP4 权重,提供 512K(524,288 token)上下文。模型采用 KDA+MLA 混合注意力;96 个 safetensors 文件共 1.561 TB,路由专家为 MXFP4,部分其他张量仍是 BF16 等精度。
难点不是“权重文件比 16 卡总显存还大”,而是装下权重后没有可靠的运行余量。 TB 和 TiB 必须统一后再比较:
| 容量项 | 核对结果 |
|---|---|
| 单卡显存 | 97,871 MiB,约 95.577 GiB |
| 16 卡物理总显存 | 1,529.234 GiB,约 1.493 TiB |
| 权重文件合计 | 1,560,936,091,448 B,约 1,453.735 GiB |
| 权重理想均摊到每卡 | 90.858 GiB |
| 理想均摊后的物理余量 | 仅 4.719 GiB/卡 |
| 单条 512K 的 MLA KV 简化下限 | 约 6 GiB/卡,尚未计 KDA 状态等开销 |
文件体积也不等于运行时分配量。加载峰值、逐 rank 不均、通信缓冲、算子工作区和 CUDA Graph 都要留空间;采用 95% 显存预算时,仅扣权重已没有余量。本次还使用更保守的 90% 引擎预算,因此选择定向 CPU 卸载。
512K 是输入与输出的总窗口,不是可再追加输出的输入长度。输出预算为 32,768 token 时,输入连同历史、模板需不超过 491,520 token。实际验收采用约 224K 和 480K 输入,给输出保留空间。
2. 技术选型:先检查卸载语义,再启动整模型
CPU 卸载不只是把参数移到内存。模型内部缓存的张量视图、预取逻辑和 forward 回调,也必须与卸载后的参数保持一致。我们先核这些条件,再进入整模型启动。
| 引擎与检查层次 | 结果 | 对部署的影响 |
|---|---|---|
| SGLang v0.5.21:固定源码 CPU 语义检查 | KDA 普通融合视图未随参数迁移,V2 缺模型回调 | 未进入整模型 CUDA 启动;不泛化为 SGLang 所有版本都不支持 CPU 卸载 |
| vLLM 0.31.0:专家层 GPU 数值检查 | 预取与 UVA 各 8/8 逐位一致;最小检查共 4 次尝试,1 次初始化失败 | 选择官方固定版本制品,继续验证整模型 |
两项检查的层次不同,不能写成两个引擎通过了完全相同的 GPU 测试。整模型随后又经历 NUMA 配置、完整权重索引两次启动失败,第三次就绪;这些失败均保留在原始账本中。
3. 架构设计:机内 NVLink,机间 RoCE,主机内存承担卸载
3.1 H20 的 NVLink 在哪里
本次两台服务器均有 NVLink/NVSwitch 互联。
NVIDIA 官方资料明确列出 HGX H20 使用第三代 NVSwitch。NVIDIA Fabric Manager:支持平台。
NVLink 负责 GPU 间高速连接,NVSwitch 将链路组成机内交换网络。设备在 PCIe 树上可见,不意味着 GPU 间通信只能走 PCIe。
这套部署要分清三个通信范围:
| 范围 | 本次配置与证据 | 对架构的意义 |
|---|---|---|
| 同一节点的 8 张 H20 | GPU 间拓扑为 NV18,Fabric Manager 运行 | TP8 留在机内 NVLink/NVSwitch 域,避免每层 TP 集合通信跨机 |
| 两个 PP 阶段之间 | 每机 8 个 400Gb/s Ethernet/RoCE 端口 Active | 跨机主要传递 PP 边界激活及必要的同步信息 |
| GPU 与主机 RAM | 定向 UVA 权重卸载,配合 NUMA 亲和性 | 属于主机内存访问路径,不能与 GPU 间 NVLink 混为一谈 |
NV18 是拓扑证据,8×400G 是端口配置;本轮没有独立测量两机 RDMA/NCCL 吞吐,也没有证明单次传输能叠加全部网口带宽。硬件存在 NVLink,同样不能直接证明某次算子已跑满链路。
3.2 为什么采用 TP8×PP2
每台机器承担一个 PP 阶段,阶段内做 TP8;VLLM_PP_LAYER_PARTITION=48,45 将 93 层分为 48 层与 45 层。两台机器共同组成一个模型实例,不能作为两个独立副本接流量。
这样做利用了机内 GPU 互联,并减少跨机集合通信的范围。PP 本身仍有阶段边界传输、负载不均和流水线气泡成本;本轮没有做 TP16 对照,因此这是经验证可运行的选型,不能称为所有布局中的最优解。
3.3 定向卸载与只读阶段索引
仅卸载 MoE 专家矩阵。 --cpu-offload-params w13_weight w2_weight 配合 UVA 32 GiB/卡,实际整参数迁移约 32.16 GiB/卡;计算仍在 GPU。NUMA 绑定影响主机侧访问,GPU0–3 对应 NUMA0,GPU4–7 对应 NUMA1,并不把 NVLink 网络切成两个四卡组。
每机只保存本阶段需要的原始分片。 节点 01 保存 51 片,节点 02 保存 48 片;部分文件两边都需要,因此两机文件数之和大于全模型的 96 个唯一分片数。
官方完整索引会要求本机存在另一阶段的文件。逐文件核对 safetensors 头部、层号与共享张量后,我们生成阶段索引并只读挂载到容器内;磁盘原始索引和权重字节不改,96 个唯一文件的 SHA 校验均通过。
以下是 eager 基线的关键参数节选,用于解释配置,不是一条完整的双机启动命令。镜像按官方版本 tag 标识为 vllm/vllm-openai:v0.31.0,制品摘要用于核验;真实部署还包含两机 rank/master 地址、网卡选择、回环 API、只读挂载和资源限额。
--tensor-parallel-size 8 --pipeline-parallel-size 2 \
--distributed-executor-backend mp --nnodes 2 \
--max-model-len 524288 --max-num-seqs 1 \
--max-num-batched-tokens 8192 --gpu-memory-utilization 0.90 \
--enforce-eager --no-async-scheduling --enable-prefix-caching \
--mamba-cache-mode align --language-model-only --moe-backend marlin \
--offload-backend uva --cpu-offload-gb 32 \
--cpu-offload-params w13_weight w2_weight \
--numa-bind --numa-bind-nodes 0 0 0 0 1 1 1 1
模型由官方 Docker 运行,容器限制 CPU、内存、swap 与进程数;--restart=no 加 12 小时超时。后面的 Graph 对照只删除 --enforce-eager,并发阶段再单独改变请求上限,避免将多个改动的效果混在一起。
4. 基线验收:缓存能缩短等待,冷文档仍需计算
首轮使用同一个 512K 引擎,先按 256K 请求上限、再按 512K 上限检查;不是两种引擎窗口的性能对照。短文本、冷暖长文档与多轮更新召回共 10 条,10/10 正确自然结束,失败、unknown、重试均为 0。
下表为首轮 eager 基线,C1,每行 n=1。TTFT 是首 token 延迟;生成阶段速度按客户端输出事件计算,区别于以完整请求墙钟为分母的输出 TPM。
| 实际输入 / 缓存 | TTFT(s) | 生成阶段(token/s) | 总 TPM | 输出 TPM |
|---|---|---|---|---|
| 224,156 / 未命中 | 180.61 | 5.16 | 63,085.15 | 45.84 |
| 224,156 / 高命中 | 3.61 | 5.60 | 589,720.97 | 265.60 |
| 480,158 / 未命中 | 421.02 | 5.46 | 63,765.70 | 21.51 |
| 480,158 / 高命中 | 2.76 | 5.46 | 944,780.95 | 285.22 |
两条暖请求分别复用 223,488 和 480,000 token,均来自 GPU 前缀缓存。总 TPM 含复用输入,不能当作新计算能力;输出 TPM 含等待,不能用生成阶段速度直接乘 60 替代。
首条短请求另有 111.27 秒首次 FlashInfer 通信 JIT 停顿,单独记录。首轮实际输出只有 45–197 token,没有验证连续生成满 32,768 token,也不构成稳定产能或长稳验收。
16 卡均有 SM、DRAM、功耗和显存同窗采样。最高单卡显存采样峰值约 91.44 GiB,不是 allocator 的瞬时峰值;不能把单卡最高值说成所有卡都达到该值,更不能仅凭显存或 GPU busy 判断通信瓶颈。
5. CUDA Graph:生成阶段加快,长文档首 token 基本不变
第二阶段重新启动 eager 基线与 Graph 候选,各一次启动,唯一配置差异是候选删除 --enforce-eager。基线 3 条、候选 5 条请求,合计 8/8 正确自然结束;其中 3 组请求构成前后对照。
引擎解析为 FULL_AND_PIECEWISE,自动启用 breakable CUDA Graph。16 卡均完成 FULL 1/1、PIECEWISE 2/2 捕获,尺寸为 [1,2]。Graph 池约 0.06 GiB/卡;KV 池由 1,234,955 降为 1,187,982 token,仍可容纳一条满窗口请求。
以下全部来自第二阶段,C1、每行 n=1,不与首轮基线或后续 C4 结果拼接:
| 输入 / 配置 | 输出 token | TTFT(s) | 生成阶段(token/s) | 总 TPM | 输出 TPM |
|---|---|---|---|---|---|
| 99 / eager | 105 | 12.34 | 4.88 | 349.46 | 179.87 |
| 99 / Graph | 105 | 1.41 | 17.99 | 1,607.90 | 827.60 |
| 224,156 冷 / eager | 131 | 179.64 | 5.46 | 65,702.68 | 38.38 |
| 224,156 冷 / Graph | 163 | 181.13 | 14.24 | 69,718.40 | 50.66 |
| 480,158 冷 / eager | 222 | 419.95 | 5.36 | 62,305.33 | 28.79 |
| 480,158 冷 / Graph | 109 | 419.10 | 11.97 | 67,202.07 | 15.25 |
生成阶段速度分别提升 3.69×、2.61×、2.23×。CUDA Graph 能减少反复提交 GPU 工作的开销;本次长 prefill 仍采用分块计算,冷长文档 TTFT 没有明显改善。短文 TTFT 则从 12.34 降到 1.41 秒,说明不能把结论简化为“Graph 只影响 decode”。
这里仍有两个限制。第一,样本是自由生成,长文档输出长度不完全相同;上表 480K 行的输出 TPM 下降,不能据此认定 Graph 让 decode 变慢。第二,生成只覆盖短答,12–18 token/s 不应被写成持续长输出或高并发的稳定指标。
GPU 板卡采样能耗也有下降,例如 480K 冷请求约 1512→1428 kJ。但输出长度不同,这只能作为本轮请求总能耗的观察,不能归因为等量工作的节能比例。暖请求和多轮召回均通过,前缀复用仍为 223,488 token。
6. 并发与排队:驻留上限不等于满长并发能力
第三阶段改为 --max-num-seqs 2,Graph 捕获尺寸 [1,2,4]。两轮互冷 256K+512K 请求对的墙钟分别为 606.82、609.87 秒,接近顺序基线的 621.85 秒;这组小样本没有显示显著的冷请求吞吐收益。
共享执行期,约 224K 请求的生成速度被另一条长 prefill 摊薄到约 0.31 token/s;暖请求对聚合生成约 17.4 token/s。冷暖表现不同,说明需要同时观察 prefill 争用、decode 和排队,不能只看配置允许多少条请求。
第四阶段将请求上限增至 4,捕获尺寸 [1,2,4,8]。三条请求几乎同时提交:约 480K 冷文档、约 224K 冷文档与 99-token 短文。
- 约 480K 队首冷文档:TTFT 422.08 秒;
- 约 224K 冷文档:TTFT 594.22 秒;
- 99-token 短文:TTFT 419.05 秒,也等待了约 7 分钟。
本次 vLLM 0.31.0、同步调度与 8192 分块配置下,队首长 prefill 占用每步预算,短请求未获得及时服务。max-num-seqs 提高可调度请求上限,并不会自动给短请求优先级;这是该配置的实测行为,不能推广到所有 vLLM 调度方式。
C4 配置的 GPU KV 池为 1,181,920 token,除以 524,288 约为 2.25。这个值只是容量比,不能向上取整为三条满窗口常驻,更不能把 max-num-seqs 4 写成“四条 512K 并行”。实际容量还受块对齐、混合状态和在途输出影响。
另一个 C1 对照将 prefill 分块改为 16384:两档冷 TTFT 改善约 5–7%,KV 池却从 1568 降至 1262 块,减少约 19%。这一交换不适合作为本次长上下文容量优先方案的默认配置。
因此,本次运维指引是顺序提交冷长文档,并避免让短请求在长 prefill 期间进入同一队列。若业务要求短请求低延迟,需要另验独立服务资源或模型支持的调度策略;不能只靠继续调大并发数解决。
7. 难点回顾:每个结论都有自己的证据范围
| 难点 | 本次处理 | 不能据此承诺的内容 |
|---|---|---|
| 容量不足 | 统一 GiB 计算,定向 UVA 卸载 | 权重文件体积就是运行显存占用 |
| 硬件互联 | 用 NV18 与 Fabric 记录区分机内、机间链路 | 标称带宽等于实际 NCCL 吞吐 |
| 卸载兼容 | 从 CPU 语义到 GPU 数值、再到整模型逐层验证 | 某个版本失败代表整个引擎都不支持 |
| 权重索引 | 校验原文件,容器内只读阶段索引 | 任意模型都能直接裁剪索引 |
| Graph 收益 | 重新建立 eager/Graph 对照 | 短答收益就是长稳、高并发收益 |
| 排队行为 | 记录三类请求 TTFT,发布提交指引 | 请求上限提高就能缩短短文等待 |
后续实验切换到了 256K 窗口,并涉及 24 GiB 卸载与 Host/文件系统 KV 分层;它们不属于本文的 512K 对照。文件系统跨引擎复用出现过正确性失败,详见第 3 篇,不能混入这里当作成功配置。
8. 在这次部署中,哪些配置值得保留
512K 阶段保留 CUDA Graph+8192 分块+UVA 32 GiB/卡,请求上限曾按用户需求设为 4。Graph 提高了本轮生成阶段速度;前缀缓存缩短重复文档等待;较小的 prefill 分块保留了更多 KV 容量。这三个作用应分别评估。
这次工作的边界同样明确:机内有 NVLink/NVSwitch,跨机仍需付出网络与 PP 的成本;512K 可以通过功能验收,冷输入仍需数分钟;请求可驻留不代表短请求能及时执行。部署交付需要把这些事实与配置一起写清。
下一篇讨论数据口径与验收方法:大模型压测方法论:如何让性能数据可信。
系列目录
- KV Cache 与前缀缓存:从原理到 99.9% 命中率的生产实践
- PD 分离实战:Prefill/Decode 拆池、配比拐点与容量规划
- GPU→内存→SSD 三级 KV 缓存:Mooncake 分层实战与跨引擎复用陷阱
- Kimi-K3 原始 MXFP4 权重512K 长上下文生产部署:双机 16 卡 TP8×PP2 与 CUDA Graph 调优(本篇)
- 大模型压测方法论:如何让性能数据可信
- 推理集群可观测性:64 卡监控体系与缓存证据链
- MiniMax-H3视频生成服务化:ComfyUI 多 GPU 编排与长任务生命周期
- 掉卡排查实录:RTX 5070 反复 Xid 79,如何排查建立证据链
- GPU对调定位法:8 卡 RTX 6000D 掉卡,如何用对调缩小故障范围
- CUDA 802 不是 NCCL 网络故障:H20 NVSwitch 物理链路排查实录
- DeepSeek-V4.1-Flash 双机 16 卡 H20 部署压测:TP8×DP2 与跨机 EP 的边界
数据声明:本文数据来自受控内部测试环境;各阶段均有限定启动/推理额度并闭账,单次观测不构成稳态产能。