高并发调度与吞吐优化
高并发调度与吞吐优化
引擎选型(见 LLM 推理引擎对比与选型) 定了之后,吞吐还能再翻几倍——靠的是调度策略。本文讲清 Continuous Batching、Prefill/Decode 分离、投机解码、张量并行,以及它们为什么能拉满 GPU。
一、Continuous Batching:消灭 head-of-line blocking
静态 Batching(朴素)的问题
传统做法是”凑一批请求,等整批都生成完才返回”:
Batch = [reqA(20 tok), reqB(200 tok), reqC(5 tok)]
→ 必须等 reqB 跑完 200 tok,A/C 才释放 → A/C 的 GPU 空等
长请求拖死短请求,GPU 利用率低。
Continuous Batching(token 级动态)
vLLM/SGLang 的做法:调度单位是 单个 token 的 step,而非整个请求。
step 1: 处理 A,B,C 的 token1
step 2: A 完成退出;新请求 D 加入;处理 B,C,D 的 token2
step 3: C 完成退出;处理 B,D 的 token...
- 短请求一完成立即释放显存/算力
- 新请求随时插入(用 PagedAttention 的块分配)
- GPU 利用率从 30-50% 提到 80%+
二、Prefill / Decode 分离:两个异构阶段
LLM 推理分两段,特征完全不同:
| 阶段 | 做什么 | 计算特征 | 瓶颈 | 优化手段 |
|---|---|---|---|---|
| Prefill | 处理整个 prompt,生成初始 KV | 大矩阵乘、可充分并行 | 算力(FLOPS) | chunked prefill、并行 |
| Decode | 逐 token 生成 | 每步只算 1 token,反复读 KV | 显存带宽(HBM) | 投机解码、KV 量化 |
为什么分离有用
- 不分离时,长 prompt 的 prefill 会阻塞正在 decode 的请求(抢占式调度,带来抖动)
- 分离后:prefill 队列和 decode 队列独立调度,decode 的 TPOT 更稳定
- 生产架构:prefill 用算力强的机器池,decode 用带宽大的机器池(异构部署)
┌── Prefill Pool (高 FLOPS) ──┐
请求 ──split──> │ 算 prompt KV │ ──KV 传入──> Decode Pool (高 HBM 带宽) ──> 逐 token 输出
└────────────────────────────┘
代表实现:DistServe、TetriInfer、以及 vLLM 的
--distributed-executor-backend思路。SGLang 也支持分离式部署。
三、投机解码(Speculative Decoding):让 decode 也”批量”
Decode 每次只产 1 token,串行、访存密集。投机解码打破串行:
1. 小草稿模型(draft) 快速"猜"接下来 n 个 token
2. 大模型(target) 一次并行验证这 n 个 token 对不对
3. 接受所有正确的前缀,丢弃第一个错误之后的 → 一步前进多 token
- 草稿模型可以是:同架构小模型、或 target 自身的浅层(MEDUSA)、或 n-gram 树
- 收益:延迟降 2-3×,吞吐升(同等延迟下多服务请求),质量不变(验证通过才接受)
- 代价:草稿模型占用额外显存;草稿不准时反而亏
MEDUSA / EAGLE
- MEDUSA:在主干上挂多个”head”并行预测多头,无需独立草稿模型
- EAGLE:用主干倒数第二层特征+小自回归头预测,命中率更高
四、Chunked Prefill:长 prompt 不卡 decode
把超长 prompt 的 prefill 切成小块(chunk),与 decode 请求交替执行:
传统:prefill 8K prompt 占满 GPU 200ms → 期间所有 decode 停
Chunked:prefill 切成 512-token 块,每块间穿插处理 decode → decode 不中断
- vLLM
--enable-chunked-prefill、SGLang 默认支持 - 代价:prefill 总时间略增,但 decode 延迟稳定性大幅改善
五、张量并行(多卡低延迟)
单卡放不下或未达延迟目标时,把权重切片到多卡:
权重按层/按 head 切到 N 张卡,每卡算一部分,all-reduce 汇总
- 张量并行度 TP=N:N 张卡协同服务单个请求 → 降低单请求延迟
- 受限于卡间互联:节点内 NVLink >> 节点间 RDMA >> PCIe
- 配合 GPU 网络 知识:TP 跨节点要走 IB/RDMA,延迟敏感场景尽量 TP 限制在单节点内
# vLLM 双卡张量并行
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \
--pipeline-parallel-size 1
六、其他吞吐杠杆
| 手段 | 作用 |
|---|---|
--max-num-seqs 调大 | 允许更多并发请求(受 KV 容量限制) |
--gpu-memory-utilization 调高 | 给 KV Cache 更多显存,撑更高并发 |
| 前缀缓存(见 KV 篇) | 多轮/Agent 省 prefill |
| 请求优先级/流式 | 长任务异步化,先返回短任务 |
| CUDA Graph | 固化 kernel 执行图,省 launch 开销(vLLM/SGLang 默认开) |
七、调度策略决策树
目标:高吞吐(成本优先)
→ Continuous Batching + 大 --max-num-seqs + Prefix Cache + 量化
目标:低延迟(体验优先)
→ TP 多卡 + Chunked Prefill + 投机解码 + 分离部署
目标:长上下文多轮 Agent
→ Prefix/Radix Cache + GQA 架构 + KV 量化
目标:极致成本(边缘)
→ GGUF 量化 + llama.cpp + 小模型
关联知识
- LLM 推理服务化知识总览 — 吞吐/延迟/成本三角
- LLM 推理引擎对比与选型 — 引擎对各类调度的支持度
- KV Cache 原理与 PagedAttention — 调度与 PagedAttention 协同
- LLM 推理量化部署 — 量化对吞吐/延迟的影响
- 生产部署与运维 — 这些策略在 K8s 上如何落地
- GPU 网络 — TP 跨节点的互联约束
参考资源
学习时间
| 阶段 | 时间 | 备注 |
|---|---|---|
| 内容创建 | 2026-07-20 | Continuous Batching、Prefill/Decode 分离、投机解码、Chunked Prefill、TP |
状态标记
📖 已掌握 — 四类调度优化原理与适用场景、TP 互联约束 📝 待补充 — Pipeline Parallel / Expert Parallel(MoE) 详解、真实压测数字对比