核心要点
先算账:1000 用户并发 vs 1000 tok/s 总吞吐 → 人均吞吐极低,排队不可避免,先确认是容量问题还是配置问题
瓶颈定位:吞吐 vs 延迟权衡、batch 是否打满(continuous batching)、KV Cache 显存是否成为并发上限、prefill vs decode 阶段、显存带宽 / 算力谁先到顶、排队时延占比
优化吞吐:vLLM 连续批处理 + PagedAttention、量化、扩容多副本、投机解码
优化体验:限流与优先级、按 SLA 分级,把有限吞吐分配给关键请求
标准回答
第一步:先算账,建立量级直觉
1000 tok/s 是集群的总吞吐上限。如果 1000 个用户真的同时在生成,理论上人均只有约 1 token/s——这远低于可用体验(通常希望每用户 20–50 tok/s)。所以第一结论是:这是容量严重不足导致的排队,光调参数救不回来,需要先判断“是真满载,还是配置没用满”。要区分两种情况:吞吐确实被硬件顶到天花板,还是 batch 没打满、调度不佳导致有效吞吐远低于硬件极限。
第二步:理解吞吐与延迟的权衡
LLM 推理里吞吐和单请求延迟是一对矛盾:增大 batch 能提高总吞吐(GPU 利用率更高),但会拉长单个请求的延迟。分析瓶颈先要明确目标是保吞吐还是保延迟,再看当前在曲线的哪个位置。
第三步:分阶段看 prefill 与 decode
- Prefill(处理输入 prompt):一次性算完整个输入,是算力(compute)密集型,长 prompt 会吃满算力;
- Decode(逐 token 生成):每步只生成一个 token,是显存带宽密集型,且要反复读写 KV Cache。
判断瓶颈在哪个阶段,决定了优化方向:prompt 很长就先优化 prefill,长输出就重点优化 decode。
第四步:定位真正的瓶颈点
逐项排查:
- batch 是否打满:有没有用连续批处理(continuous batching)?传统静态 batch 要等一批全部结束才换下一批,GPU 大量空转;连续批处理能在每步动态加入/移除请求,把利用率拉满。没用上它,吞吐就远没榨干;
- KV Cache 显存:每个并发请求都要为它的上下文常驻一份 KV Cache,显存往往才是真正的并发上限——不是算力不够,而是显存装不下更多并发序列。看显存占用是否逼近上限、有没有因显存碎片浪费;
- 显存带宽 vs 算力谁先到顶:用 profiler 看 decode 阶段是带宽打满还是算力打满,对症下药;
- 排队时延:观测请求在队列里等了多久,排队占端到端延迟的比例,确认瓶颈是排队还是计算。
第五步:优化手段
- vLLM / 连续批处理 + PagedAttention:把 KV Cache 像操作系统分页一样管理,大幅减少显存碎片、提升并发数和吞吐,是性价比最高的一招;
- 量化:INT8 / FP8 / 权重量化降低显存占用和带宽压力,腾出空间装更多并发、提速 decode;
- 扩容 / 多副本:1000 并发对 1000 tok/s 本质是容量不够,水平扩展副本、加卡是根本解;
- 投机解码(speculative decoding):用小模型起草、大模型校验,降低单请求延迟、提高有效吞吐;
- 限流与优先级、按 SLA 分级:既然总吞吐有限,就主动管理——对请求限流、设优先级队列,把吞吐优先分给付费 / 关键请求,普通请求降级或排队,保证关键体验不崩。
结论
先用“算账”确认这是容量与排队问题,再从 batch 利用率、KV Cache 显存、prefill/decode、带宽 vs 算力逐层定位真正瓶颈;优化上以 vLLM 连续批处理 + 量化压榨单卡吞吐为先,配合扩容根治容量,再用限流分级把有限资源用在刀刃上。
常见误区
⚠️ 常见踩坑
不先算账就盲目调参,期待靠优化把人均吞吐从 1 tok/s 拉到可用,实则是容量根本不够;以为瓶颈一定是算力,忽视 KV Cache 显存才是并发上限;仍用静态 batch 导致 GPU 大量空转却抱怨“吞吐上不去”;只追吞吐把 batch 开到极大,结果单请求延迟爆炸;没有限流和优先级,高峰期所有请求一起劣化。
追问
追问 1:为什么说 KV Cache 显存常常才是并发的真正上限?
因为每个正在生成的请求都要把它的上下文(已处理的所有 token)对应的 Key/Value 缓存常驻在显存里,序列越长、并发越多,KV Cache 占用就越大,且随生成不断增长。很多时候 GPU 算力还没打满,显存就已经被 KV Cache 吃光,无法再接纳新的并发请求,于是请求只能排队——瓶颈表现为“显存装不下更多并发”而非“算不过来”。这也是 PagedAttention 的价值:用分页管理减少碎片、提高显存利用率,从而在同样显存下支持更多并发序列。
追问 2:连续批处理(continuous batching)相比静态批处理好在哪?
静态批处理把一批请求凑齐一起算,必须等批里最慢(最长输出)的请求结束才能释放、换下一批,期间先完成的请求占着位置、GPU 大量空转,短请求还被长请求拖累。连续批处理以 token 为粒度调度:每一步生成后,已完成的请求立刻离开、新到的请求随时插入正在运行的 batch,GPU 始终保持高利用率。结果是吞吐显著提升、平均等待时间下降,尤其在请求长度差异大、并发高的线上场景收益巨大,是 vLLM 等推理引擎的核心机制。
追问 3:投机解码为什么能在不堆硬件的情况下提升有效吞吐?
自回归解码每步只生成一个 token,受显存带宽限制、GPU 算力其实没吃满。投机解码让一个小而快的草稿模型一次性猜测接下来的若干 token,再用大模型一次前向并行校验这些草稿:猜对的部分直接采纳,猜错的从分歧处继续。由于大模型的并行校验能一次确认多个 token,相当于把多步串行解码压缩成更少的大模型前向,单请求延迟下降、单位时间产出的 token 变多,从而在不增加卡的前提下提高有效吞吐。代价是要额外维护草稿模型,且收益取决于草稿命中率。
🔗 相似问题
同一考点的不同问法,面试官可能换着问,一起刷更稳
没找到想看的面试题?把你想看的告诉我们 →
延伸学习
按主题分类的相关资源,便于系统复习