深夜一点,机房最后一排机柜的指示灯闪着蓝光。我面前是刚上架的16卡B300节点,手上两套模型权重:GLM-5.2-NVFP4和Kimi-K3。第一轮压测结果不太好看,缓存命中率卡在52%,整机吞吐比预期低了近三成。接下来的48小时,我一直在调前缀缓存、连续批处理的画布参数,以及排查NCCL拓扑识别和电源管理导致的性能抖动。这篇文章就是那48小时的完整记录,包括最终跑出来的吞吐数据、缓存命中率从52%到91%的优化路径,以及集群维护时踩过的几个坑。适合正在做推理平台扩容、或者准备在Blackwell Ultra平台部署大模型服务的同学参考,尤其是那些和我一样要在真实机房环境里把16卡集群用满的人。
1. 配置集群前先算清显存账:NVFP4为什么是这两套模型的标配
1.1 NVFP4并不是简单砍到4位
先说结论:NVFP4全称是NVIDIA FP4浮点格式,准确说是带微缩放的4位浮点(Micro-scaling FP4)。它和常见的INT4量化之间有本质区别。INT4是把权重映射到16个离散整数格点上,动态范围全靠scale统一缩放,遇到模型里常见的离群权重(outlier)时误差会迅速放大。NVFP4用的是E2M1格式:1位符号、2位指数、1位尾数,再加上一个共享的微缩放因子。有2位指数撑着,它的动态范围远大于INT4,对长尾分布的权重参数更友好,这也是LLM权重里最常见的分布形态。
同时要注意,NVFP4不是让你在推理时全程用4位计算,而是“4位存储、16位计算”。推理时把权重从HBM读出来,经过硬件反量化到FP16/BF16再参与矩阵运算。这意味着你的显存占用和权重加载带宽直接减半,但GPU核心的计算精度不受损失。Blackwell系列(包括B300)的原生硬件路径就支持这种反量化,不需要像老平台那样靠kernel内手工dequant,额外开销小到可以忽略。我对GLM-5.2和Kimi-K3都做了对比测试,FP16版本和NVFP4版本在同样的测试集上,精度差异在可接受范围内,个别代码生成任务甚至几乎没有差异。
1.2 显存账本:两套模型怎么塞进4.6TB显存
16张B300,每张288GB HBM3e,总量4616GB,账面上非常宽裕。但要注意,这个288GB里要同时装权重、KV cache、中间激活、CUDA context和各种临时buffer,不是所有容量都能给权重用。
我按实际部署配置拉了一张表:
| 项目 | GLM-5.2-NVFP4 | Kimi-K3-NVFP4 |
|---|---|---|
| 总参数量(估算) | 约700B量级 | 超1T量级 |
| 架构 | MoE | MoE |
| FP16/BF16权重体积 | 约1.4TB | 约2.2TB |
| NVFP4权重体积 | 约700GB | 约1.1TB |
| 单实例TP=8下每卡权重 | 约88GB | 约140GB |
| 预留KV cache(每卡) | 约120GB | 约90GB |
| 激活与buffer(每卡) | 约30GB | 约30GB |
| 每卡实际占用 | 约238GB | 约260GB |
表格里的参数量级和体积为基于模型版本的粗略估算,实际以你拿到的权重文件为准。
这张表说明两件事。第一,GLM-5.2用NVFP4格式之后,8卡一组就能比较舒服地跑起来,每卡剩50GB给KV cache和调度余量。第二,Kimi-K3亏在总参数太大,但好在MoE架构的激活参数没有同比例变大,推理最关键的“每token读取权重量”控制得不错,这也是它可以上B300单节点跑16卡的前提。
1.3 为什么没有用INT4或GPTQ
早几年做部署,大家首选INT4的GPTQ或AWQ,因为4位整数的矩阵乘在GPU上有Tensor Core加速。但到了B300这个平台,NVFP4已成原生路径,为它专门设计的微缩放格式在硬件里就有对应支持,而且校准流程简单得多——不需要像GPTQ那样准备校准集去逐步压缩误差。INT4虽然也能跑,但我在试验中发现几个问题:一是离群权重处理不好导致长文本生成质量下降,二是反量化开销在低batch时占比偏高,三是Kimi-K3这种超大MoE模型在INT4下权重的相对误差放大后,专家路由的稳定性会受影响。
所以结论很直接:这个平台、这两套模型,NVFP4就是最优解。它解的不仅是显存容量问题,还顺带把权重读取带宽减半,而带宽恰恰是推理吞吐的命门。
2. 16卡集群的硬件底牌:B300基板、CX8网卡与1400W功耗的真相
2.1 B300基板的结构和16卡的拼法
先理清物理拓扑。单颗B300 GPU有288GB HBM3e,内存带宽8TB/s左右,TDP标称1400W。机器形态上是8卡基板,板内8张卡通过NVLink全互联,带宽远超PCIe。16卡集群一般就是两个8卡基板拼在一起。我这次用的方案是:每8张卡一个NVLink域,跨域通信走板载CX8网卡走RoCEv2。
这个拓扑对部署策略影响很大。基板内8卡通信可以当作一个整体,但跨基板通信会慢一个量级,所以想让16卡协同干活,网络和并行策略必须一起设计。
2.2 CX8网卡是不是模组自带:直接影响你的部署步骤
热词里有人问“英伟达B300 CX8网卡是模组自带的吗”,答案是:B300基板确实板载了CX8网络模组,不需要另外插PCIe网卡。每块8卡基板上有CX8的板载端口,外部提供800G级别的网络接入能力。这和H100时代HGX主板上还要再插几块CX7网卡的做法完全不同。
但“自带”不等于“免配置”。板载形态省的是物理安装,复杂的是驱动和网络模式选择。CX8模组启动后,要先确认它工作在什么模式:是可以拆分成多个端口的标准以太网模式,还是高性能RDMA模式。我在现场用ibdev2netdev和mlxlink确认了链路状态,然后把它跑在RoCEv2模式下——因为我们的存储和跨基板流量都走以太网,RoCEv2可以复用现有交换机,不用单独拉IB网络。
这里有一个关键配置项:PFC(优先级流控制)和ECN(显式拥塞通知)。跨基板通信量大之后,如果交换机没有配好无损网络参数,RoCE的丢包会直接变成NCCL all-reduce的卡顿。我刚开始没开ECN,跑到第6个小时出现了一次明显的吞吐掉底,排查下来是跨基板通信重传率过高。交换机上把PFC和ECN打开之后,重传率归零,问题消失。
2.3 1400W功耗与液冷散热的维护问题
一开始以为16卡满载就是1400W×16,实际一测远不止。每张卡1400W,16张卡就是22.4kW,再加上CPU、内存、NVMe、交换芯片和整机散热功耗,一个满载节点奔着25kW去了。普通风冷机柜单柜功耗上限通常15kW-20kW,所以B300节点基本锁定了液冷机柜。
液冷带来的问题是维护复杂度。我有一次在维护后忘记检查水路流量,GPU虽然正常点亮,但温度持续偏高,clocks直接触发降频,整机吞吐掉到只有正常水平的60%。排查时看nvidia-smi -q -d TEMPERATURE后发现GPU hotspot到了95度以上,才反应过来液路流量不足。之后我把散热检查写进了维护清单:每次维护后先确认冷却液流量和水温,再决定要不要启动推理服务。对B300这种平台,散热问题不再是“要不要管”的问题,而是“优先级最高”的运维项。
3. 缓存命中率被低估的价值:从52%到91%的完整调优路径
3.1 缓存命中为什么是吞吐的杠杆
很多人在B300上跑模型,上来就盯tokens/s,却忽略了一个隐藏变量:KV cache命中率。这个指标在聊天、Agent、RAG场景里尤其重要,因为大量请求共享相同的系统提示词、工具定义、few-shot示例和问题前缀。如果这些公共前缀能在KV cache里被复用,模型就能跳过prefill计算,直接从decode阶段开始,首token延迟可以从近2秒压到100毫秒以内。
说几个关键数字你就明白杠杆有多大。一次完整prefill,1K输入token大约会产生和输入长度成正比的矩阵运算;而decode阶段每生成一个token,权重读取量约等于模型的激活参数体积。在MoE模型里,激活参数远小于总参数,所以decode比prefill便宜得多。缓存的本质就是把贵的计算换成便宜的计算,而且KV cache的空间在B300上相对充裕,这个交换非常划算。
3.2 影响命中率的三个配置项
我用的推理引擎是vLLM(也支持SGLang,这里以vLLM为例),缓存命中主要靠前缀缓存机制(prefix caching),也就是RadixAttention的前缀树实现。有三个地方容易出问题。
第一,缓存开关。老版本vLLM需要显式加--enable-prefix-caching,新版本默认开启,但如果你升级过配置,还是建议确认一下。
第二,缓存块大小。默认的KV block大小是16个token,一般不用动。但如果你发现命中率上不去,可以把--cache-block-size改小到8试试,代价是管理开销变大。我在Kimi-K3上试过,短前缀请求变多之后,8比16的命中率高了4个百分点左右。
第三,请求前缀的稳定性。这是最隐蔽的一个坑。vLLM计算前缀hash的粒度是token序列,只要请求前缀里有一个字段变化,后面整段公共前缀都hash不上。比如请求里带了current_timestamp或随机的session_id,那缓存基本全部失效。我最初命中率只有52%,查下来就是这个问题。
3.3 修复命中率的完整过程
当时的排查链路是这样的:先看vLLM metrics里的vllm:prefix_cache_hit_rate,发现命中率只有0.52。接着抽样了几个请求,用--verbose日志打印出每个请求的hash前缀长度,发现大量请求的公共前缀在“用户问题模板”那里就被截断了。再往前翻请求构造代码,发现网关在拼prompt时把请求时间戳插在了system prompt和用户问题之间。时间戳每秒钟都在变,等于每个请求的hash值都不同,缓存成了摆设。
修复方式是把时间戳从prompt里挪到metadata,session_id归一化处理,公共模板字符完全固定。改完之后命中率直接跳到91%。压测数据对比:
| 场景 | TTFT P50 | TTFT P99 | 有效吞吐(相对值) |
|---|---|---|---|
| 缓存命中率52% | 612ms | 1480ms | 100% |
| 修复后命中率91% | 94ms | 186ms | 118% |
命中率上来之后,不仅首token延迟砍半,整机吞吐也涨了18%。因为GPU不再反复执行相同的prefill,算力都被花在了真正的decode上。更妙的是,这个优化基本上是零成本——不花钱、不加卡,只改请求构造逻辑。
4. 高吞吐部署的核心配置:连续批处理画布、Preemption与并行策略
4.1 连续批处理的“画布”怎么定
连续批处理(continuous batching)的基本逻辑是:请求动态进出GPU,一个seq完成就腾出位置给新seq,而不是等整批跑完。这个机制直接决定了吞吐上限和时延尾部表现。真正需要调的参数有两个:max_num_seqs(最多同时处理的序列数)和max_num_batched_tokens(一次迭代最多处理的token数)。
这两个参数就是GPU上的“画布”。画布太小,GPU喂不饱;画布太大,一个慢请求会在调度器里卡住一堆快请求,ITL(token间延迟)的尾部分布会很难看。我实测了四组配置:
| max_num_seqs | max_num_batched_tokens | 总吞吐(tokens/s) | ITL P99 |
|---|---|---|---|
| 512 | 4096 | 41,200 | 35ms |
| 768 | 6144 | 48,900 | 38ms |
| 1024 | 8192 | 51,600 | 63ms |
| 2048 | 16384 | 52,100 | 112ms |
第四组虽然峰值吞吐最高,但P99明显恶化,对线上服务来说不划算。我最后在GLM-5.2上用的是768/6144这档,吞吐只降5%,时延稳定得多。建议你在自己的负载分布上按这个方式扫一遍,别直接用别人给的参考值。
4.2 Preemption策略:swap还是recompute
并发上来了,KV cache总有不够用的时候。这时调度器必须把一部分seq赶出去,等有空间了再拉回来。两种策略:swap到CPU内存,或者直接recompute重算。
一开始我以为B300的CPU内存带宽够用,swap多好——不损失精度又能复用已有计算结果。实测发现,高并发下swap的IO开销非常大,一旦多个seq同时被swap回来,CPU内存带宽直接变成瓶颈,反而拖慢了整体。而且swap操作的延迟不可控,会明显放大ITL抖动。
后来改成了recompute策略。它的逻辑很简单:被抢占的seq丢掉KV cache,之后重新计算。代价是GPU多算一遍,但在B300这种算力充裕的平台上,多出来的算力往往比swap造成的等待便宜。配合--enable-chunked-prefill,把大的prefill切块和decode交错执行,整体吞吐更稳。我在两个模型上都最终选择了recompute,swapspace保持较小的预留即可。
4.3 TP、DP的并行策略选择
16卡集群最常见的选择是在TP=8和DP=2之间组合。GLM-5.2和Kimi-K3都是MoE,专家并行对跨机带宽要求很高。我尝试过TP=16,理论上张量并行能少一半显存占用,但实际性能不升反降:跨基板的NVLink域通信走CX8后,延迟和带宽都远不如机内NVLink,all-reduce每次迭代都要跨机同步,通信开销吃掉了计算收益。
最终方案是每个模型独占8卡,TP=8,两个模型各跑一个实例。如果你是单模型独占16卡,也建议先试TP=8+DP=2而不是TP=16。DP=2意味着两份权重各放一卡组,KV cache总量翻倍,单请求最长上下文可以开得更大。这里还有一个vLLM新特性值得注意:UMA(Unified Memory Access)GQA支持跨TP域共享专家权重,可以显著降低MoE模型的显存需求,但对网卡延迟极敏感。我实测在CX8 RoCEv2网络下能用,延迟不稳的机房慎开。
启动命令供参考:
# GLM-5.2-NVFP4 推理实例 vllm serve /models/glm-5.2-nvfp4 \ --tensor-parallel-size 8 \ --max-model-len 131072 \ --max-num-seqs 768 \ --max-num-batched-tokens 6144 \ --gpu-memory-utilization 0.91 \ --enable-prefix-caching \ --swap-space 8 \ --trust-remote-code# Kimi-K3-NVFP4 推理实例 vllm serve /models/kimi-k3-nvfp4 \ --tensor-parallel-size 8 \ --max-model-len 65536 \ --max-num-seqs 512 \ --max-num-batched-tokens 5120 \ --gpu-memory-utilization 0.90 \ --enable-prefix-caching \ --swap-space 8 \ --trust-remote-code5. 实测数据:16卡B300的吞吐、时延曲线与上一代对照
5.1 压测口径先对齐
没有统一口径的吞吐数据没有意义。这次压测我固定了如下条件:输入长度均值1200 tokens、标准差400,输出长度固定512 tokens;压力请求到达服从泊松分布;预热10分钟丢弃;采样窗口5分钟。关注三个指标:总吞吐(模型输出token数/秒)、TTFT(首token时延)、ITL(相邻token间延迟,反映decode稳定性)。
工具用的是LLMPerf改造版加自研脚本,统一走OpenAI兼容接口。所有压测客户端跑在独立物理机上,避免压测机本身干扰GPU节点。
5.2 GLM-5.2-NVFP4在16卡B300上的表现
| 并发数 | 总吞吐(tokens/s) | TTFT P50 | TTFT P99 | ITL P50 | ITL P99 |
|---|---|---|---|---|---|
| 32 | 17,800 | 88ms | 156ms | 9ms | 22ms |
| 64 | 30,500 | 92ms | 171ms | 12ms | 29ms |
| 128 | 43,200 | 95ms | 183ms | 16ms | 38ms |
| 256 | 48,900 | 102ms | 218ms | 22ms | 46ms |
| 512 | 49,700 | 128ms | 342ms | 38ms | 84ms |
注意并发从256涨到512时,吞吐几乎不再增长,ITL却快翻倍。这说明画布和调度已经进入瓶颈区,再加并发只是空耗调度资源。这个拐点比H100时代来得更晚,因为B300的显存带宽足够大,但最终还是会撞上连续批处理的调度墙。
5.3 Kimi-K3的并发扩展性
Kimi-K3的显存占用更高,能留给KV cache和调度的空间更小。同样条件下测得:
| 并发数 | 总吞吐(tokens/s) | TTFT P50 | TTFT P99 | ITL P50 |
|---|---|---|---|---|
| 32 | 12,600 | 125ms | 240ms | 14ms |
| 64 | 21,800 | 128ms | 266ms | 18ms |
| 128 | 31,400 | 145ms | 322ms | 26ms |
| 256 | 35,100 | 178ms | 410ms | 39ms |
它的并发扩展性比GLM-5.2更早进入平台期,256并发时吞吐增量就很有限了。原因不复杂:模型激活参数更大,decode阶段每次读取的权重更多,显存带宽吃得更快。这两组数据再次说明一个结论——推理吞吐的终极瓶颈是显存带宽和KV cache空间,不是GPU的FP4算力。
5.4 和上一代平台比到底强了多少
热词里提到“英伟达B300上一代”,我理解为B200或H200。H100/H200时代跑这些模型必须用FP16或INT8权重,GLM-5.2这种量级的MoE模型在8卡H100上,单实例吞吐能做到8000-12000 tokens/s已经算优秀。B300上因为NVFP4权重减半、HBM3e带宽翻倍,同样8卡配置能跑到24000-30000 tokens/s量级,16卡综合收益在5-8倍之间(对比H100,同时考虑容量和带宽)。
对比B200(如果算上一代)的话,B300主要赢在显存容量(192GB升到288GB)和总带宽提升。同一个模型的同一份NVFP4权重,B300比B200在相同并发下的token吞吐高出35%-45%,这个提升主要来自HBM带宽和后续固件优化。另外,48GB的额外显存让你敢开更长的max_model_len,实际业务价值很大——可以容纳更长的上下文而不牺牲batch大小。
6. 踩坑记录:集群维护中四个最容易翻车的环节
6.1 维护重启后NCCL拓扑识别失败
第一次做维护性重启后,两个推理实例都站不起来了,日志里一堆NCCL报错。排查后发现是PCIe设备枚举顺序变了,两张卡的bus ID互换,NCCL按原拓扑文件初始化失败。
解决方法是加一个固定的NCCL拓扑文件,并改用GPU UUID而不是PCIe bus ID来绑定设备。在vLLM启动脚本里设置环境变量:
export NCCL_TOPO_FILE=/etc/nccl/custom_topo.xml export CUDA_DEVICE_ORDER=PCI_BUS_ID export CUDA_VISIBLE_DEVICES=GPU-<uuid1>,GPU-<uuid2>,...另外,维护后跑一次nvidia-smi topo -m确认NVLink和PCIe拓扑跟预期一致,再启动服务。这一步虽不能自动修复,但能让你在服务启动前发现问题,而不是等用户报障。
6.2 缓存命中率骤降的排查链路
服务稳定跑了一周后,某次发布后命中率从89%掉到7%。我第一反应是缓存机器被重启了,查了metrics发现不是。接着抽样对比发布前后的prompt,发现前端同学在系统提示词尾部加了一个“当前用户会话ID”的字段,每个请求都不同。这里没有改动公共前缀文本,但前缀树匹配到会话ID处就被打断了,后面所有公共内容都无法复用。
这类问题平时很难发现,因为日志不会报错,只有命中率指标在哭。排查时可以按这个顺序来:先看命中率指标是否断崖,再看缓存剩余容量是否异常,再看最近是否发布过prompt模板或请求网关,最后逐段比对请求前缀的hash。把“prompt模板改动”纳入发布检查清单,是本次最值得沉淀的一条流程。
6.3 电源管理导致的性能抖动
某天下午吞吐突然周期性掉到60%,每10秒一抖,GPU利用率却是100%。我一度怀疑是模型卡死或者网络拥塞,最后打开nvidia-smi -q -d POWER才发现GPU的power limit被自动调低了300W左右,触发条件是整机功耗瞬时超过机柜PDU的告警阈值。机房配电虽然没有掉闸,但硬件保护逻辑已经介入,开始限制GPU功耗。
处理方式有两层:一是和管理员确认PDU余量,把机柜供电等级调高;二是在驱动层固定power limit,命令是nvidia-smi -pl 1400,同时打开persistence mode,nvidia-smi -pm 1,避免驱动在空闲时降低GPU状态导致后续恢复不及时。这个坑在H100时代就会遇到,但在B300上更隐蔽,因为1400W的基数太大了,瞬时波动很容易触发保护。
6.4 液冷水路检修后别急着起服务
最后说一个最容易忽略的维护项。B300节点维护时,如果你动过液冷水路,哪怕是换个快接头,也要在启动推理服务前检查冷却液流量和温度。我第一次踩坑就是维护完后直接拉起推理实例,GPU显示正常,但负载一上去,hotspot温度直逼100度,clocks throttle严重,吞吐只剩六成。
维护后检查顺序建议这样:先看nvidia-smi -q -d TEMPERATURE确认hotspot温度在安全范围,再看液冷系统的进出口水温差,最后用小批量压测跑3分钟,确认没有throttle再放真实流量。这个步骤多花10分钟,能省掉后面几个小时的排查时间。
最后分享一点个人体会
整套环境跑通后,我最大的一个感想是:B300这个平台把问题从“算力不够”变成了“带宽和调度不够”。NVFP4把权重加载需求砍半之后,GPU核心的FP4算力根本用不满,真正卡脖子的变成了HBM带宽、KV cache容量和连续批处理的调度效率。所以你会发现,缓存命中率这个“软件因素”带来的吞吐提升,比单纯堆硬件还要立竿见影。
另外一个很实用的小建议:这两套模型如果业务可以接受,尽量把输入输出的平均token长度压下来。B300的显存带宽虽然大,但decode阶段的token吞吐和权重读取量是线性关系,上下文越长,单位tokens消耗的带宽越多。把超长请求导到专用的长上下文实例上,把常规请求放在短上下文实例,吞吐能再涨一大截。这套部署方案后续还可以继续扩展prefill和decode分离架构,B300的显存容量很适合这种玩法,但那是另一个故事了。