4.1 单节点高并发部署:把一台 8 卡机器跑成「吞吐怪兽」 单节点部署是绝大多数团队真正落地的第一站,也是性价比最高的一步:没有跨节点网络这个最大的不确定因素,NVLink 域内带宽充足,调优路径清晰。这一节我用一个典型的 8 卡场景,带你完整走一遍「从默认配置到跑满 GPU」的实战,并且把每一步为什么要这么拧旋钮讲透。 先定基线:这台机器能喂多大的模型 动手写启动命令前,先用「三个旋钮」模型盘一遍你的硬件边界。假设你手上是单机 8 卡,每卡 80GB(如 H100/A100 80G),整机能用的显存上限约 640GB。但 DeepSeek V4 是 MoE,总参数量巨大,即便只激活部分专家,全部专家权重在推理时仍要常驻显存。
单节点部署是绝大多数团队真正落地的第一站,也是性价比最高的一步:没有跨节点网络这个最大的不确定因素,NVLink 域内带宽充足,调优路径清晰。这一节我用一个典型的 8 卡场景,带你完整走一遍「从默认配置到跑满 GPU」的实战,并且把每一步为什么要这么拧旋钮讲透。
动手写启动命令前,先用「三个旋钮」模型盘一遍你的硬件边界。假设你手上是单机 8 卡,每卡 80GB(如 H100/A100 80G),整机能用的显存上限约 640GB。但 DeepSeek V4 是 MoE,总参数量巨大,即便只激活部分专家,全部专家权重在推理时仍要常驻显存。
一个粗略的显存账(定性,记住量级即可):
我的主张:单节点第一步一定是「TP 开满」。8 卡机器就把 tensor-parallel-size 设成 8,利用节点内 NVLink 吃尽带宽。不要上来就琢磨 PP/EP 的复杂组合,先把单节点这 8 张卡作为一个整体用透——除非权重单靠 TP8 仍放不下,才引入 EP 切专家(MoE 本来就该上 EP,这里 EP 和 TP 叠加是标准打法)。
在敲下启动命令之前,有两个动作能帮你省掉后面大半天 debug:
第一,先跑通最小可跑示例。用默认参数、单请求、短 prompt 先起一次,确认模型能加载、能出 token。这步把「环境问题」和「调优问题」隔离开——如果最小示例都报错,那是环境/版本/权重问题,不是你旋钮拧错了。第一章 1.3 就专门讲最小可跑示例,这里复用它的精神:先证明「能跑」,再谈「跑好」。
第二,盯住启动日志里的显存与并行信息。vLLM 启动时通常会打印权重占用的显存、KV Cache 能分配的最大 block 数、实际生效的 TP/EP 等。这些信息是你后续调旋钮的基线——比如日志说 KV 池只能容纳 2000 个序列,而你设了 max-num-seqs 256 还有余量,那说明并发旋钮还能往上顶;反之若日志警告 KV 池紧张,就该先砍 max-model-len 或量化。
下面是一份典型启动长相(参数名以你实际版本为准,这里给出通用形态,便于理解每个旋钮的作用,不保证某版本逐字可用):
# 单节点 8 卡,TP=8,针对 MoE 叠加 EP python -m vllm.entrypoints.openai.api_server \ --model <你的 DeepSeek V4 模型路径或名称> \ --tensor-parallel-size 8 \ --gpu-memory-utilization 0.85 \ --max-model-len 8192 \ --max-num-seqs 256 \ --max-num-batched-tokens 8192 \ --enable-chunked-prefill \ --dtype auto
逐一解释这几个旋钮:
--tensor-parallel-size 8:把模型横切到 8 卡,节点内 NVLink 扛通信。--gpu-memory-utilization 0.85:允许 vLLM 用掉单卡 85% 显存做权重+KV 池。剩下 15% 是安全垫,防止碎片和突发激活把卡顶爆。--max-model-len 8192:控制最长上下文。这个值直接决定 KV Cache 的「单位成本」——序列越长,每个请求占的 KV 越多,能并发的越少。先压到业务确实需要的值,别无脑设 128k。--max-num-seqs 256:同时能排进调度器的最大请求数。这是并发旋钮,开太小吞吐上不去,开太大显存被 KV 吃爆。--max-num-batched-tokens 8192:一个 batch 内 token 总量上限,和连续批处理配合,决定「一次前向塞多少活」。--enable-chunked-prefill:把长 prompt 的 prefill 切片,避免一个超长请求独占 batch 把别人饿死,对尾延迟友好。写完启动命令,别急着宣布成功。高并发部署的真理是:不压测你不知道瓶颈在哪。 我见过太多人「感觉跑得挺快」就上线,结果真实流量一来,P99 从 200ms 飙到 8s。
压测要同时盯四个指标,缺一不可:吞吐(tokens/s)、TTFT(首 token 延迟)、TPOT(每 token 延迟)、P99(尾延迟)。一个典型压测长相(用并发客户端持续打,混合短长 prompt):
并发 128: 吞吐 1420 tok/s TTFT P50=180ms P99=620ms -> 卡在 KV 预算 并发 256: 吞吐 1610 tok/s TTFT P50=210ms P99=1500ms -> 开始排队 并发 384: 吞吐 1630 tok/s TTFT P99=3200ms -> 吞吐见顶, 延迟恶化
从这条曲线能读出关键事实:吞吐在并发 256 左右就见顶了,再往上加并发只是让 P99 变烂,产能不增反降。这就是「并发旋钮拧过头」的典型信号——你喂的请求超过了 GPU 真正能并行的上限,多余的全在排队。
讲一个我反复验证过的调优路径,比空讲参数更有用。起点是「几乎全默认」:gpu-memory-utilization 0.9、max-num-seqs 偏小、max-model-len 32768。
第一轮:OOM。 一上来就 OOM。原因:max-model-len 给太大,KV Cache 池被上下文长度预算撑爆,权重都没地方放。动作:把 max-model-len 砍到业务真实需要的 8192。这一刀直接腾出大量显存。
第二轮:吞吐低、P99 高。 能跑了,但并发 128 时 P99 就到 1.5s。看监控发现 GPU 利用率只有 40%,明显「喂不饱」。原因:max-num-seqs 和 max-num-batched-tokens 偏小,batch 没塞满。动作:把 max-num-seqs 提到 256、max-num-batched-tokens 提到 8192,并确认开 chunked-prefill。GPU 利用率爬到 85%+,吞吐翻倍,P99 反而降了——因为更满的 batch 让每张卡都在干活,没有空转。
第三轮:逼近极限。 继续加并发,吞吐在 256 见顶,P99 恶化。此时三个旋钮已接近平衡:显存利用率 0.9 是安全上限、并发 256 是这条硬件的甜点、TP8 已开满。再要提升只有两条路:要么量化省权重显存(把更多预算让给 KV,从而塞更多并发),要么上多节点(进入 4.2)。我选择先试量化:权重从 BF16 降到 FP8,显存占用降约一半,KV 池预算变宽松,max-num-seqs 能再往上顶,吞吐又涨一截。
这个流程的精髓在于:每次只动一个旋钮,看指标往哪走,再决定下一个动作。高并发调优最忌讳一次性改五个参数然后说不清是哪刀生效的。
在单节点语境下,量化是「不换硬件、再榨一截」的关键手段。常见取向:
一个判断:如果你的瓶颈是「KV 预算不够导致并发上不去」,优先试 KV Cache 量化或砍 max-model-len;如果是「权重放不下」,再上权重量化。方向错了事倍功半。
收尾给你三条我反复强调、踩过坑才信的铁律,再加一张常见翻车对照表:
铁律一:先 NVLink 域内 TP 开满,再谈别的。 单节点不把 TP 用透就去搞 EP/PP,是本末倒置。
铁律二:max-model-len 是显存刺客。 无脑给大值,KV 预算会悄悄吃掉本该用于并发的显存。按业务真实上限设,能省一大笔。
铁律三:并发不是越大越好。 越过甜点后,加并发只涨尾延迟不涨吞吐。找到「吞吐见顶、P99 开始恶化」的拐点,就是你的稳态并发。
| 翻车现象 | 根因 | 处置 |
|---|---|---|
| 启动即 OOM | max-model-len / gpu-util 过大 | 砍上下文、降 gpu-util 到 0.85 |
| GPU 利用率低、吞吐差 | 并发旋钮太小、batch 没塞满 | 提 max-num-seqs / batched-tokens |
| P99 飙高但吞吐没涨 | 超过并发甜点 | 回落并发,或量化腾预算 |
| 长请求卡住短请求 | 未开 chunked-prefill | 启用分块 prefill |
| TP 一大吞吐反降 | 跨 NUMA / 非 NVLink 拓扑 | 查 nvidia-smi topo -m,TP 留在 NVLink 域 |
很多人把 max-num-seqs 和 max-num-batched-tokens 混为一谈,其实它们管的是不同维度。max-num-seqs 限制「同时在跑的请求数」,max-num-batched-tokens 限制「一次前向里这些请求合计的 token 数」。一个长 prompt 请求可能占了大量 token 却只算一个 seq,此时即便 max-num-seqs 没满,batched-tokens 也可能先顶到上限,导致新请求进不来。
实操含义:如果你的流量以长 prompt 为主(比如文档摘要、长文生成),batched-tokens 往往比 seqs 先成为瓶颈,要优先调它;如果以大量短请求为主,seqs 更敏感。这也是为什么压测要混合长短 prompt——只打短请求会让你误判 batched-tokens 的余量。
调优不是靠感觉,是靠监控。除了压测客户端报出的吞吐/延迟,我还建议实时看 GPU 侧指标:
这些指标和「三个旋钮」是一一对应的:利用率低→动并发旋钮,KV 紧→动显存/上下文旋钮,通信高→动并行旋钮且确认拓扑。
很多人的压测是「打 30 秒看个峰值」就收工,这是危险的。高并发部署必须做持续压测:用稳态并发连续打 30 分钟以上,观察显存是否缓慢爬升(内存/KV 泄漏的信号)、是否有零星 OOM、P99 是否随时间漂移。我见过配置「跑一分钟完美、跑十分钟开始丢请求」的情况,根因是 KV 碎片在长期运行后无法回收。所以验收标准里的「稳定」不是口号,是必须实测的硬指标。
把 4.1 讲的内容收成一个可勾选的清单,你照着打钩就能确认这一节真的做完了:
八条全过,单节点这关就算真正过了。下一节我们把视野拉到多节点。
一句话带走:单节点高并发的本质,是在 TP 开满的前提下,把 gpu_memory_utilization、max_model_len、max_num_seqs、max_num_batched_tokens 这四个旋钮拧到「显存不爆、GPU 喂饱、尾延迟可接受」的交点。下一节,当你需要超越单节点的边界时,我们讲多节点集群怎么扩。
如果这一节你只记住一句话,我希望是:「单节点的瓶颈,九成能用『TP 开满 + 并发甜点 + 量化腾预算』这三板斧解决,剩下的是监控和稳定。」至于具体的数字(0.85、256、8192),它们都是我这台示例机器的甜点,不是你的。把方法带走,把数字忘掉,遇到你的硬件重新测一遍——这才是这一节真正的产出。