1. 从一次线上告警说起:Token 生产效率到底在优化什么
凌晨两点,推理集群的 P99 延迟从 800ms 飙到 4.2s,值班同学在群里甩了一张监控图:GPU 利用率 98%,但每秒输出 Token 数反而掉了三成。这不是算力不够,而是典型的 Token 生产效率塌陷——芯片在满负荷空转,真正吐出来的有效 Token 却越来越少。
我做了六年推理基础设施,从早期单卡部署到现在的千卡集群,踩过的坑基本都围绕一个核心命题:如何让每一瓦电、每一块钱芯片成本,产出尽可能多且稳定的 Token。这里的 Token 不只是大模型里的文本单元,它已经变成衡量 AI 基础设施效率的通用货币。你去看任何一家做推理服务的团队,内部考核指标里一定有"单卡 Token 吞吐"和"每百万 Token 成本"这两个数。
这篇文章面向三类人:一是正在做推理服务部署的工程师,二是负责集群资源调度的运维同学,三是需要给老板解释"为什么加了卡还是慢"的技术负责人。我会从芯片选型、推理引擎调优、集群调度、供电散热四个层面,把 Token 生产效率这件事拆开讲透,每个环节都给出可复现的参数和踩坑记录。全文基于我实际经手的几个生产集群,数据做了脱敏,但方法论可以直接抄。
先说结论性的判断:Token 生产效率不是单点优化,它是一个从硅片到机柜到调度器的全栈问题。你在推理引擎里调一个 batch size,可能让供电模块的温度上升 8 度,进而触发降频,最后 Token 吞吐反而下降。这种跨层耦合,才是这件事真正难的地方。
2. 芯片层:算力、显存带宽与 Token 产出的真实关系
2.1 为什么"算力强"不等于"Token 多"
很多人选卡只看 TFLOPS,这是个巨大的误区。大模型推理分两个阶段:Prefill(预填充)阶段是计算密集型,吃的是算力;Decode(解码)阶段是访存密集型,吃的是显存带宽。而 Token 生产效率主要由 Decode 阶段决定,因为每生成一个 Token 都要把整个模型权重和 KV Cache 读一遍。
我实测过一组数据,在同一台机器上跑 7B 模型,FP16 精度:
| 芯片类型 | 标称算力 | 显存带宽 | 单卡 Token/s(batch=1) | 单卡 Token/s(batch=32) |
|---|---|---|---|---|
| A 卡 | 300 TFLOPS | 900 GB/s | 42 | 680 |
| B 卡 | 400 TFLOPS | 600 GB/s | 35 | 510 |
| C 卡 | 200 TFLOPS | 1200 GB/s | 58 | 920 |
你看,算力最低的 C 卡,Token 吞吐反而最高。原因很简单:Decode 阶段每生成一个 Token 需要读取的字节数是固定的,带宽决定了单位时间能读多少遍权重,也就决定了能生成多少 Token。算力在这个阶段大部分时间是闲置的。
提示:选推理卡时,先算你的模型在 Decode 阶段的带宽需求,再去看卡的显存带宽,最后才看算力。顺序反了,钱就白花了。
2.2 显存容量如何卡住你的并发上限
显存带宽决定速度,显存容量决定并发。KV Cache 是吃显存的大户,它的计算公式是:
KV Cache 大小 = 2 × 层数 × 注意力头数 × 头维度 × 序列长度 × batch_size × 精度字节数以一个 13B 模型为例,40 层,40 个头,头维度 128,FP16 精度(2 字节),序列长度 4096:
单条序列 KV Cache = 2 × 40 × 40 × 128 × 4096 × 2 = 3.35 GB也就是说,光是一条 4K 上下文的请求,就要占 3.35GB 显存。一张 24GB 的卡,扣掉模型权重(13B FP16 约 26GB,得用两张卡或者量化),留给 KV Cache 的空间非常紧张。这就是为什么很多团队发现"卡没跑满但就是加不了并发"——显存被 KV Cache 吃光了。
我的做法是上 PagedAttention 类的显存管理方案,把 KV Cache 按页切分,碎片率能从 60% 降到 5% 以内。实测下来,同样的卡,并发数能提升 2.3 倍,Token 吞吐直接翻倍。这个优化不需要换硬件,纯软件层面就能拿到,性价比极高。
2.3 量化:用精度换 Token 的边界在哪
量化是提升 Token 生产效率最直接的手段。INT8 量化能让显存占用减半,带宽压力减半,Token 吞吐理论上翻倍。但这里有个边界:量化会损失精度,而精度损失在某些任务上会表现为"生成的 Token 质量下降",需要重试或人工修正,反而拉低了有效 Token 产出。
我做过一组对比测试,用同一个模型跑代码生成任务:
| 量化方案 | 显存占用 | Token/s | 代码通过率 | 有效 Token 效率 |
|---|---|---|---|---|
| FP16 | 100% | 100 | 82% | 82 |
| INT8 | 52% | 185 | 79% | 146 |
| INT4 | 28% | 310 | 61% | 189 |
注意最后一列"有效 Token 效率",是我自己定义的指标:Token/s 乘以任务通过率。INT4 虽然原始吞吐最高,但通过率掉得厉害,有效效率反而不如 INT8。所以量化不是越激进越好,要看你服务的任务类型。对话类任务对精度容忍度高,INT4 可以上;代码和数学推理类,INT8 是更稳的选择。
3. 推理引擎:把芯片潜力榨干的调优实战
3.1 推理引擎选型的三个硬指标
市面上的推理引擎很多,我评估时只看三个硬指标:连续批处理(Continuous Batching)支持、PagedAttention 支持、量化内核成熟度。这三个决定了你能不能把芯片的 Token 生产效率压榨到极限。
连续批处理是分水岭。传统静态批处理要等一个 batch 里所有请求都生成完才能接下一批,短请求被长请求拖死,GPU 利用率经常掉到 40%。连续批处理让每个请求生成完就立刻退出、新请求立刻补位,利用率能稳定在 85% 以上。我实测过,同一个模型同一张卡,开连续批处理前后,Token 吞吐差了 2.8 倍。
PagedAttention 解决的是显存碎片问题,前面讲过了。量化内核成熟度则决定了你敢不敢上 INT8/INT4——有些引擎的量化内核写得不好,实际加速比只有 1.2 倍,还不如不量化。
3.2 关键参数调优:batch size 不是越大越好
这是我最想强调的一点。很多人以为 batch size 拉满就能最大化 Token 吞吐,实际上存在一个拐点,过了拐点吞吐反而下降。
原因是:batch size 增大,单次前向的计算量增大,但每个 Token 的边际收益递减;同时 KV Cache 占用线性增长,显存压力上升,可能触发换页或 OOM。更隐蔽的是,大 batch 会让单次前向耗时变长,首 Token 延迟(TTFT)飙升,用户体验崩掉。
我的一般调优流程是这样的:
- 固定序列长度分布(用真实流量采样),从 batch=8 开始,每次翻倍
- 记录每个 batch size 下的 Token/s 和 TTFT
- 找到 Token/s 增长斜率明显变缓、且 TTFT 还在可接受范围内的点
- 在这个点附近做细粒度扫描(比如 24、32、40、48)
实测一个 7B 模型在 A 卡上的结果:
| batch size | Token/s | TTFT (ms) | 显存占用 |
|---|---|---|---|
| 8 | 210 | 45 | 38% |
| 16 | 380 | 62 | 52% |
| 32 | 620 | 98 | 74% |
| 48 | 680 | 156 | 89% |
| 64 | 655 | 240 | 96% |
拐点在 48 附近,64 时吞吐已经下降,TTFT 也翻倍了。最终我选的是 40,留一点显存余量应对突发长序列。
注意:这个拐点会随模型大小、序列长度、卡型变化,千万别照搬别人的数字,一定要自己扫一遍。
3.3 投机解码:用一个小模型换 2 倍吞吐
投机解码(Speculative Decoding)是我近一年用得最多的加速手段。原理是:用一个小模型(draft model)先快速生成几个候选 Token,再用大模型一次性验证。因为大模型验证多个 Token 的成本和生成一个差不多,所以只要小模型的命中率够高,整体吞吐就能大幅提升。
我实测的数据:7B 主模型配 0.5B draft 模型,命中率 72% 时,Token 吞吐提升 1.9 倍;命中率 85% 时,提升 2.4 倍。命中率取决于 draft 模型和主模型的分布接近程度,一般同系列的小模型效果最好。
这里有个坑:draft 模型也要占显存和算力。如果你的卡本来就紧张,加 draft 模型可能得不偿失。我的经验是,显存占用在 70% 以下时上投机解码划算,超过 85% 就别折腾了,先把显存问题解决。
4. 集群调度:让 Token 产出在规模上不掉链子
4.1 单机优化到顶后,瓶颈转移到了哪里
单卡调优做完,Token 吞吐能提升 3 到 5 倍。但当你把规模扩到几十上百张卡时,会发现整体吞吐并没有线性增长,甚至出现"加卡反而变慢"的诡异现象。这时候瓶颈已经从芯片转移到了集群调度层。
我遇到过最典型的问题:请求分发不均。负载均衡器用的是轮询策略,但每个请求的序列长度差异巨大,有的 200 Token,有的 8000 Token。轮询导致某些节点堆积了一堆长请求,排队时间爆炸,而另一些节点闲着。整体 GPU 利用率看着有 70%,但有效 Token 产出只有理论值的 40%。
解决办法是改成基于负载感知的调度:每个节点实时上报自己的队列深度和预估完成时间,调度器把新请求发给预估完成时间最短的节点。这个改动让我们的集群有效吞吐提升了 55%,而且不需要加任何硬件。
4.2 连续批处理在集群层面的坑
单机的连续批处理很美好,但集群层面会引入新问题:请求在节点间迁移时,KV Cache 怎么办?
早期我们的做法是请求一旦分配到某个节点就不再迁移,但这导致节点故障时请求全部失败,重试成本极高。后来改成 KV Cache 分片存储,配合请求迁移,故障时能把 KV Cache 一起搬走,重试几乎无感。代价是引入了一层 KV Cache 的网络传输开销,实测在万兆网络下,迁移一个 4K 上下文的请求大约增加 120ms,可以接受。
另一个坑是批处理的公平性。连续批处理下,长请求会一直占着位置,短请求不断插队,导致长请求的完成时间被无限推迟。我们后来加了优先级队列,给每个请求设一个 deadline,快超时的请求优先调度,P99 延迟从 8s 降到了 2.3s。
4.3 弹性扩缩容:Token 需求波峰波谷的应对
Token 需求有明显的波峰波谷,白天高晚上低,差两三倍很正常。如果按峰值配置资源,低谷期就是纯浪费;按均值配置,高峰期就排队。
我们的方案是分层扩缩容:
- 热层:常驻实例,覆盖日均需求的 60%,响应延迟最低
- 温层:按需拉起,覆盖到 90% 分位,冷启动约 30 秒
- 冷层:峰值兜底,冷启动约 3 分钟,用更便宜的卡
关键是温层和冷层的冷启动时间要压住。模型加载是主要耗时,我们用内存映射加预加载,把 7B 模型的加载时间从 45 秒压到了 12 秒。再配合请求排队时的预热,用户基本感知不到扩容过程。
5. 供电与散热:被低估的 Token 生产效率杀手
5.1 降频:Token 吞吐的隐形天花板
这一节是我最想写给那些"机房温度一高就变慢"的团队看的。GPU 有温度墙和功耗墙,一旦触发就降频,而降频直接表现为 Token 吞吐下降。
我实测过:一张标称 350W 的卡,在散热良好的机柜里能稳定跑满,Token/s 是 620;换到散热差的机柜,核心温度到 83 度触发降频,Token/s 掉到 480,降了 22%。更坑的是,这种下降是渐进的,监控上 GPU 利用率还是 98%,你根本看不出问题,只有对比 Token 吞吐才发现。
所以我的第一条建议是:把 GPU 核心温度和降频次数纳入核心监控指标,和 Token 吞吐放在同一个看板上。一旦发现温度上升伴随吞吐下降,先查散热,别急着优化软件。
5.2 供电质量对稳定性的影响
供电问题比散热更隐蔽。GPU 瞬时功耗波动很大,Decode 阶段相对平稳,但 Prefill 阶段会有尖峰。如果电源功率余量不足,或者供电线路压降大,会导致 GPU 触发保护性降频甚至重启。
我们的经验是:电源功率按 GPU 标称功耗的 1.5 倍配置,别按 1.2 倍省那点钱。另外,同一路供电上不要挂太多 GPU,瞬时尖峰叠加会超过线路承载。我们曾经把 8 张卡挂在同一路 30A 的电路上,跑批量 Prefill 时频繁触发保护,后来拆成两路就好了。
还有一个细节:供电模块的电容老化会导致电压纹波增大,长期看会影响 GPU 稳定性。机房运行两年以上的,建议定期检查供电质量,用示波器看纹波,超过规格就换电源模块。
5.3 散热方案选型:风冷、液冷还是浸没
散热方案直接决定你能把 Token 生产效率压榨到什么程度。我三种都用过,说说实际感受:
| 方案 | 单机柜功率上限 | 降频风险 | 改造成本 | 适用场景 |
|---|---|---|---|---|
| 风冷 | 15 kW | 中高 | 低 | 中小规模、旧机房 |
| 冷板液冷 | 50 kW | 低 | 中 | 中大规模、新建机房 |
| 浸没液冷 | 100 kW | 极低 | 高 | 超大规模、高密度 |
风冷的问题是热空气回流,机柜上层的卡总是比下层热,降频不一致,导致集群里各节点性能参差。我们后来用盲板封堵空位、调整风扇曲线,把温差从 12 度压到了 4 度,Token 吞吐的方差小了一半。
冷板液冷是我目前最推荐的方案,改造成本可控,散热能力足够,而且噪音小。浸没液冷散热最好,但维护麻烦,换卡要捞出来,适合那种一两年不动的稳定集群。
提示:散热改造的投入产出比很高。我们花在液冷改造上的钱,大约 8 个月就从提升的 Token 吞吐里赚回来了。
6. 常见问题与排查技巧实录
6.1 Token 吞吐突然下降的排查顺序
线上最怕的就是吞吐突然掉。我总结了一套排查顺序,按这个走基本能定位:
- 先看温度:GPU 核心温度、显存温度、降频计数。温度问题占我遇到案例的 40%
- 再看显存:是否有 OOM、换页、碎片率飙升。显存问题占 25%
- 看请求分布:序列长度分布是否突变,是否有异常长请求。占 20%
- 看调度:节点负载是否均衡,是否有节点假死。占 10%
- 最后看软件:引擎版本、参数是否被改。占 5%
这个顺序的逻辑是:从硬件到软件,从底层到上层,先排除最容易被忽略的物理因素。
6.2 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决方向 |
|---|---|---|---|
| 吞吐下降但利用率高 | 降频 | 查温度和降频计数 | 改善散热、降功耗墙 |
| 加卡不加速 | 调度不均 | 看各节点队列深度 | 改负载感知调度 |
| 并发上不去 | 显存碎片 | 看 KV Cache 碎片率 | 上 PagedAttention |
| 首 Token 延迟高 | batch 过大 | 扫 batch size 曲线 | 降 batch、加优先级 |
| 长请求拖慢整体 | 批处理不公平 | 看请求完成时间分布 | 加 deadline 调度 |
| 量化后质量下降 | 量化过激 | 对比任务通过率 | 退回 INT8 |
6.3 几个反直觉的实操心得
第一个心得:别迷信峰值吞吐,要看稳定吞吐。我见过太多团队把 batch size 调到极限,跑分很好看,但线上跑两小时就开始降频、OOM、重试,实际有效吞吐还不如保守配置。我现在一律留 15% 的显存和功耗余量,稳定性优先。
第二个心得:监控要成对看指标。单看 GPU 利用率没意义,要和 Token 吞吐一起看。利用率高但吞吐低,说明在做无用功;利用率低但吞吐高,说明优化到位了。我习惯把这两个指标画在同一张图上,一眼就能看出问题。
第三个心得:优化要按投入产出比排序。软件优化(调度、批处理、量化)通常投入小见效快,先做;硬件优化(换卡、液冷)投入大,后做。我一般先花两周把软件榨干,再评估硬件投入,这样能避免花冤枉钱。
7. 一个真实集群的优化全过程复盘
最后分享一个我经手的完整案例,把前面讲的东西串起来。这是一个 32 卡的推理集群,服务一个 13B 模型,优化前日均 Token 产出 1.2 亿,每百万 Token 成本 18 元。
第一步做的是监控补齐。之前只有 GPU 利用率,我加了 Token 吞吐、温度、降频计数、显存碎片率、队列深度五个指标。补完监控当天就发现,有 6 张卡长期在降频,原因是机柜下层进风被挡住。
第二步是散热整改。清理进风、加盲板、调风扇曲线,降频卡从 6 张降到 0 张。这一步没动任何软件,Token 吞吐就涨了 18%。
第三步是推理引擎调优。开连续批处理、上 PagedAttention、扫 batch size 到 40、加投机解码。这一套组合拳下来,单卡 Token 吞吐从 380 涨到 890,翻了 2.3 倍。
第四步是集群调度改造。改成负载感知调度加优先级队列,集群有效吞吐又涨了 55%,P99 延迟从 6.8s 降到 2.1s。
第五步是弹性扩缩容。上分层扩缩容,低谷期关掉 40% 的实例,成本直接降下来。
最终结果:日均 Token 产出从 1.2 亿涨到 4.7 亿,每百万 Token 成本从 18 元降到 4.3 元。整个优化周期六周,硬件投入只有散热整改那部分,其余全是软件和调度层面的改动。
这个案例最想说明的一点是:Token 生产效率优化不是买更贵的卡,而是把现有资源的每一分潜力都榨出来。芯片、引擎、调度、散热,四个层面任何一个有短板,整体效率就上不去。而补齐短板的过程,往往不需要花大钱,需要的是系统性的排查和调优。
我个人在实际操作中的体会是,这套方法论里最值钱的不是某个具体参数,而是"成对看指标、按投入产出比排序、留余量保稳定"这三个习惯。参数会随硬件和模型变化,习惯不会。你把这三个习惯养成了,换任何芯片、任何模型,都能快速找到优化路径。