Dynamic Batching(动态批处理)
3 秒看懂
一句话:让 GPU 在推理时”来多少算多少、攒够就跑”,而不是傻等固定数量的请求到齐——把延迟和吞吐之间的矛盾,用动态拼批的策略化解掉。
一句话判断:Dynamic Batching 是 LLM 推理服务端最核心的系统级优化之一,直接影响 GPU 利用率和推理成本,是 vLLM、TensorRT-LLM、Triton 等推理引擎的关键差异点。
3 分钟产业解释
为什么需要它?
想象一家餐厅的后厨:
- 没有 Dynamic Batching(静态批处理):厨师要等满 8 个一模一样的菜名才开始做,哪怕前面已经来了 6 个”番茄炒蛋”,也必须再等 2 个,同时对所有菜品用同一时间出锅——谁先做完都得等最慢的那道。
- 有了 Dynamic Batching:厨师看到 6 个”番茄炒蛋”,够一锅了就先炒;中间又来 3 个”麻婆豆腐”,又够一锅了就做;先做完的先出,不用等。
产业意义
在 LLM 推理场景下,每个请求的输入/输出长度差异巨大(从几十 token 到数千 token)。如果用静态批处理:
- 短请求被长请求”绑架”:短请求早就生成完了,但必须等同批最长的请求完成才能返回。
- GPU 算力浪费严重:批内已结束的请求占用显存和计算资源却不产出。
- 成本居高不下:同样的 GPU 集群,吞吐可能只有 Dynamic Batching 方案的几分之一。
Dynamic Batching 直接把推理服务的吞吐/成本效率拉升一个量级,是推理侧降本的核心手段之一。
15 分钟专家深入
核心机制分层
Dynamic Batching 在实践中逐步演化出三个层次:
| 层次 | 名称 | 核心思想 | 代表系统 |
|---|---|---|---|
| L1 | 请求级动态批处理 (Request-level) | 在一个时间窗口内把到达的请求拼成一个 batch,统一送入 GPU | NVIDIA Triton Dynamic Batching |
| L2 | 连续批处理 / 迭代级调度 (Continuous / Iteration-level Batching) | 在 decoding 的每个 step 级别调度:已完成的请求退出、新请求加入,batch 组成动态变化 | Orca (OSDI’22)、vLLM、TensorRT-LLM (In-flight Batching) |
| L3 | Prefill-Decode 分离调度 (Disaggregated Scheduling) | 把计算密集的 prefill 阶段和访存密集的 decode 阶段拆到不同 GPU/实例上,各自独立做 dynamic batching | Splitwise (ISCA’24)、DistServe 等研究原型 |
关键技术细节
1. 为什么 L1 不够?——“bubble” 问题
在请求级批处理中,一旦一个 batch 启动,批内所有序列必须走完所有 decoding step。短序列早早 EOS 但仍然占用 GPU 资源(显存中的 KV cache、线程束中的计算),造成 bubble(气泡),即无效计算。
时间 →
┌──────────────────────────────────────────┐
│ Request A (短): ████████░░░░░░░░░░░░░░░░ │ ← 已完成,但被迫等待
│ Request B (中): ████████████████████░░░░░ │ ← 还在跑
│ Request C (长): █████████████████████████ │ ← 最慢
└──────────────────────────────────────────┘
░░░ = bubble(浪费的 GPU 资源)
2. Continuous Batching 如何消除 bubble?
以 Orca 提出的 iteration-level scheduling 为例:
Step 1: [A, B, C] 一起 decode
Step 2: [A, B, C] 一起 decode
Step 3: [A 完成, 退出] → [B, C, D(新到)] 一起 decode ← A 的槽位立刻被 D 占用
Step 4: [B, C, D] 一起 decode
...
关键机制:
- 迭代级调度器(Iteration-level Scheduler):每个 decoding step 之前重新决定 batch 内容。
- 请求退出/加入:已生成 EOS token 的请求立即退出,释放 KV cache;队列中等待的新请求立即补入空位。
- 避免 padding:不同请求解码不同数量的 token,调度器逐请求追踪状态,不再需要对齐到最长序列。
3. Prefill-Decode 分离与异构批处理
最新的研究观察到:
- Prefill 阶段:计算密集(大量矩阵乘法处理 prompt),算术强度高,适合用计算带宽大的 GPU。
- Decode 阶段:访存密集(逐 token 生成,每步只计算一层的激活,但需要加载全部模型权重),瓶颈在显存带宽,需要高 HBM 带宽。
两者混合在同一 GPU 上会导致:
- Prefill 请求的长计算阻塞 Decode 请求的低延迟需求。
- Decode 请求的低算术强度拉低 GPU 计算利用率。
分离后各自做独立的 Dynamic Batching:
- Prefill 实例做请求级动态拼批(按 prompt 长度和 max batch size 聚合)。
- Decode 实例做连续批处理(高频迭代调度)。
技术原理
一、传统静态批处理 vs 动态批处理
========== 静态批处理 (Static Batching) ==========
请求队列: [Req1, Req2, Req3, ...]
│
▼
┌─────────────────┐
│ 等待 batch 满 │ ← 固定 batch_size = N,必须攒满
│ 或超时触发 │
└─────────────────┘
│
▼
┌─────────────────┐
│ Pad 到统一长度 │ ← 短序列用 padding 填齐
│ 统一送入 GPU │
└─────────────────┘
│
▼
┌─────────────────┐
│ 全部生成完成 │ ← 最慢的请求决定整体延迟
│ 统一返回 │
└─────────────────┘
二、动态批处理的核心调度逻辑
========== Dynamic Batching (请求级) ==========
while True:
1. 收集 [0, max_wait_time] 窗口内到达的所有请求
2. 按以下约束拼批:
- 总 token 数 ≤ max_tokens_in_batch ← 关键:按 token 预算而非请求数
- 请求数 ≤ max_batch_size
- 满足 SLO 的延迟约束
3. 对齐 padding(仅在 batch 内部对齐)并送入 GPU
4. 处理完成后立即返回该批次结果
5. 回到步骤 1
三、连续批处理(Continuous Batching)的调度状态机
========== Iteration-level Scheduling ==========
Global State:
active_batch = [] # 当前正在 decode 的请求集合
waiting_queue = FIFO() # 等待进入的请求
Per Decode Step:
┌──────────────────────────────────────────┐
│ 1. Check active_batch 中每个请求: │
│ - 若 generated EOS 或 max_len → 退出 │
│ - 否则 → 留在 batch │
│ │
│ 2. 计算空闲槽位数 = max_batch │
│ - len(active_batch) │
│ │
│ 3. 从 waiting_queue 取出 ≤ 空闲槽位数 │
│ 的新请求,执行 prefill,加入 batch │
│ │
│ 4. 对 active_batch 执行一步 decode │
└──────────────────────────────────────────┘
四、关键参数与约束
| 参数 | 含义 | 典型取值范围(估算) |
|---|---|---|
max_batch_size | 一个 decode step 中同时处理的最大请求数 | 取决于 GPU 显存,7B 模型在 A100-80G 上可支持数百(估算) |
max_tokens_in_batch | 一个 batch 中所有请求的 token 总量上限 | 与 KV cache 显存直接相关 |
max_wait_time | 请求级动态批处理的最长等待窗口 | 通常 1–10ms 级别,需权衡延迟与吞吐 |
KV cache 预算 | 每个请求 prefill 后预留的 KV cache 页数 | vLLM 中按 page 为单位管理,每页含固定 token 数 |
chunked prefill | 将长 prompt 的 prefill 分块执行,穿插 decode | 减少 prefill 对 decode 延迟的干扰 |
五、与 PagedAttention / KV Cache 管理的协同
Dynamic Batching 要求频繁地”加入/退出”请求,这要求 KV cache 的分配和释放足够灵活:
- 传统方式:为每个请求预分配连续的 KV cache 空间(按 max_seq_len),退出后才能释放 → 碎片化严重。
- PagedAttention(vLLM 提出):将 KV cache 按固定大小的”页”(page/block)管理,类似操作系统虚拟内存分页。请求动态加入时按需分配页,退出时页立即可回收。
- 这样 Dynamic Batching 才能在每个 iteration 灵活增减请求,不被 KV cache 碎片化所阻碍。
KV Cache 显存管理对比:
传统连续分配:
┌─────────┬─────────┬─────────┬─────────┐
│ Req A │ Req B │ Req C │ (空闲) │
│ (已结束)│ (还在跑)│ (还在跑)│ │
│ [浪费!] │ │ │ │
└─────────┴─────────┴─────────┴─────────┘
→ A 结束后其空间不能立即给 D 用(若不移动 C)
PagedAttention 分页管理:
┌──┬──┬──┬──┬──┬──┬──┬──┐
│A1│B1│C1│D1│A2│B2│C2│空│ ← 每页独立,A 的页可立即回收
└──┴──┴──┴──┴──┴──┴──┴──┘
→ A 结束后 A1、A2 立即可被新请求复用
技术演进史
| 时间 | 事件 | 意义 |
|---|---|---|
| ~2010s | 深度学习推理框架(TensorFlow Serving 等)引入基础的请求级 dynamic batching | 允许在时间窗口内拼批,但仍是静态 batch 执行 |
| 2022 | Orca 论文(OSDI’22,首尔大学 + 微软研究院)提出 iteration-level scheduling | 首次系统化提出”连续批处理”:每一步调度、请求动态进出,从根本上消除 bubble |
| 2023 | vLLM(UC Berkeley)发布,集成 PagedAttention + Continuous Batching | 将连续批处理与高效 KV cache 管理结合,成为开源 LLM 推理的事实标准引擎之一 |
| 2023 | NVIDIA TensorRT-LLM 引入 In-flight Batching | 商业推理栈跟进 continuous batching 概念 |
| 2023–2024 | Splitwise / DistServe 等提出 Prefill-Decode 分离 | 将 dynamic batching 推进到跨实例/跨节点级别 |
| 2024 | Chunked Prefill、Prefix Caching 等成为主流优化 | Dynamic Batching 与更多调度策略融合,调度器复杂度持续上升 |
| 2024–2025 | Disaggregated serving(PD 分离)在生产环境落地 | Dynamic Batching 从单节点调度器演变为集群级调度系统 |
技术路线对比
| 维度 | 静态批处理 (Static Batching) | 请求级动态批处理 (Request-level Dynamic) | 连续批处理 (Continuous Batching) | Prefill-Decode 分离 + 各自动态批处理 |
|---|---|---|---|---|
| 调度粒度 | 整个 batch 一次完成 | 每个 batch 一次完成,但 batch 内容动态组合 | 每个 decode step 调度一次 | 按阶段(prefill/decode)独立调度 |
| Bubble 现象 | 严重(短请求等长请求) | 有所缓解但仍存在 | 基本消除 | 完全消除 + 异构优化 |
| GPU 利用率 | 低(估算 30–50%,场景相关) | 中等(估算 50–70%) | 高(估算 80–95%+) | 最高(各阶段匹配硬件特性) |
| 实现复杂度 | 低 | 中等 | 高(需要 iteration-level scheduler) | 很高(跨实例调度、网络传输 KV cache) |
| KV Cache 效率 | 浪费严重(预分配 max_len) | 有改善 | 高(配合 PagedAttention) | 最高 |
| 延迟公平性 | 差(长请求拖累短请求) | 有改善 | 好(短请求快速退出) | 最好 |
| 典型系统 | 早期 TF Serving, ONNX Runtime | NVIDIA Triton Dynamic Batching | vLLM, TensorRT-LLM, SGLang | Splitwise (研究) |
| 适用场景 | 离线批处理、对延迟不敏感 | 传统 CV 模型推理 | LLM 在线推理(主流) | 大规模 LLM 集群、追求极致吞吐和延迟 |
上下游
上游(依赖什么)
┌─────────────────────────┐
│ 模型架构与参数 │
│ (决定 KV cache 大小、 │
│ prefill/decode 计算比) │
└───────────┬─────────────┘
│
┌──────────────────────┼──────────────────────┐
│ │ │
┌──────▼──────┐ ┌────────▼────────┐ ┌────────▼────────┐
│ GPU 硬件 │ │ 推理框架/引擎 │ │ KV Cache 管理 │
│ (显存容量、 │ │ (调度器实现) │ │ (PagedAttention │
│ 带宽、算力) │ │ │ │ 等) │
└─────────────┘ └─────────────────┘ └─────────────────┘
- GPU 显存:决定了 max_batch_size、max_context_len 的上限,是 Dynamic Batching 参数空间的硬约束。
- 模型结构:注意力机制类型(MHA/MQA/GQA)影响 KV cache 大小,进而影响可同时服务的请求数。
- KV Cache 管理策略:PagedAttention、RadixAttention(SGLang)等是 Dynamic Batching 高效运行的基础设施。
下游(影响什么)
- 推理服务 API 的响应质量:TTFT(Time to First Token)、TPS(Tokens per Second)、端到端延迟。
- GPU 集群利用率 → 单位推理成本($/M tokens)。
- API 定价策略:更高效的 batching → 更低的边际成本 → 更具竞争力的定价。
- 用户体验:动态批处理使得高并发下仍能维持可接受的延迟 SLO。
关键指标
| 指标 | 含义 | 为什么与 Dynamic Batching 相关 |
|---|---|---|
| Throughput (req/s 或 tokens/s) | 每秒处理的请求数或 token 数 | Dynamic Batching 直接提升吞吐 |
| TTFT (Time to First Token) | 从请求到达到第一个 token 输出的时间 | Prefill 阶段被长 batch 中其他请求延迟 → batching 策略影响 TTFT |
| TPOT (Time Per Output Token) | 每个输出 token 的平均生成时间 | Decode 阶段 batch 越大,单 token 延迟可能增加(但吞吐提升) |
| P50/P99 Latency | 延迟分位数 | Dynamic Batching 需要在平均吞吐和尾部延迟间权衡 |
| GPU Utilization / SM Occupancy | GPU 计算单元利用率 | 好的 batching 策略让 GPU 始终”吃饱” |
| KV Cache Utilization | KV cache 显存的使用效率 | PagedAttention 减少碎片化,直接支撑更灵活的 batching |
| Goodput | 满足 SLO 的有效吞吐 | 不仅看吞吐,还要看多少请求在延迟约束内完成 |
供需与市场数据
需求端
- LLM 推理请求的特征:输入输出长度高度不确定、实时性要求高、并发波动大。这些特征使得 Dynamic Batching 不是”锦上添花”而是”刚需”。
- 随着 Agent / RAG / 长上下文应用爆发,单请求 token 数上升,对 batching 策略的精细化要求更高。
供给端
- 开源引擎竞争激烈:vLLM、SGLang、TensorRT-LLM 在 batching 策略上持续迭代,是社区最活跃的优化方向之一。
- 云厂商差异化:各大云厂商的推理服务(如 AWS SageMaker、Azure ML、Google Vertex AI)在底层均实现了某种形式的 Dynamic Batching / Continuous Batching,差异主要体现在调度精细度和与硬件的协同优化上。
- 推理芯片厂商:除 NVIDIA 外,AMD(ROCm + vLLM 支持)、华为昇腾(MindSpore Serving)等也在跟进。
市场规模
Dynamic Batching 本身不是一个独立市场,而是推理引擎/推理服务的核心技术组件。其价值体现在推理服务市场的规模中——据多家行业报告估算,全球 LLM 推理服务市场在 2025 年已达数百亿美元量级,且仍在高速增长。Dynamic Batching 的优化直接影响该市场的利润率结构。
代表公司与资本映射
| 公司/项目 | 角色 | 与 Dynamic Batching 的关系 |
|---|---|---|
| NVIDIA | 推理硬件 + 软件栈 | TensorRT-LLM 的 In-flight Batching;Triton 的 Dynamic Batching;在 disaggregated serving 方向持续探索 |
| vLLM (UC Berkeley → Anyscale/社区) | 开源推理引擎 | 连续批处理 + PagedAttention 的标杆实现,广泛被企业和云厂商采用 |
| SGLang (UC Berkeley) | 开源推理引擎 | 在 continuous batching 基础上加入 RadixAttention(前缀缓存)、compressed FSM 等,面向结构化输出优化 |
| CoreWeave | GPU 云服务 | 底层推理服务依赖高效的 batching 策略来最大化 GPU 利用率 |
| Lambda / Together AI / Fireworks AI | 推理 API 服务商 | 自研或基于 vLLM/TRT-LLM 的 batching 优化是核心竞争力之一 |
| Anyscale | Ray + 推理平台 | Ray Serve 提供了生产级的 batching 入口,vLLM 的重要贡献方 |
| Anthropic / OpenAI / Google DeepMind | 模型推理方 | 内部推理基础设施必然采用先进的 dynamic/continuous batching,但具体实现未公开 |
产业映射
核心判断
- Dynamic Batching 是推理侧”降本增效”的核心杠杆:在模型参数量和推理需求同步增长的背景下,不优化 batching 意味着 GPU 利用率低下 → 推理成本高企 → 无法支撑大规模应用落地。
- 开源引擎(vLLM、SGLang)的快速迭代正在压缩商业推理栈的差异化空间:纯靠 batching 策略难以构成持久壁垒,真正的壁垒在于与硬件的深度协同(如 NVIDIA 全栈)或与上层应用的深度集成。
- Prefill-Decode 分离是下一阶段工程焦点:在集群级别实现高效调度(包括 KV cache 的跨节点传输)的平台,能在大规模推理场景下获得显著的成本优势。这催生了对高带宽互联(如 NVLink、RoCE、定制交换机)的需求。
受益标的类型
- GPU/加速器厂商(NVIDIA、AMD 等):更高效的 batching → 更高的 GPU 利用率 → 客户同样的业务需求下 GPU 采购量可能减少,但推理市场规模增长抵消这一影响;同时 software stack 的 batching 能力成为差异化卖点。
- 推理服务公司(CoreWeave、Together AI 等):batching 效率直接影响利润率。
- 推理芯片创业公司:如果能证明在特定场景下更优的 batching+硬件协同方案,存在差异化机会。
- 网络/互联基础设施:PD 分离架构对节点间 KV cache 传输的带宽和延迟提出新需求。
常见误读纠偏
❌ 误读 1:“Dynamic Batching 就是 Continuous Batching”
纠偏:两者相关但不等价。
- Dynamic Batching(广义):泛指任何动态组合请求的批处理策略,包括请求级时间窗口内的拼批。
- Continuous Batching(特指 iteration-level scheduling):是 Dynamic Batching 的一种更高级形式,调度粒度从”请求批次”细化到”每个 decode step”,允许请求每一步动态进出。
- 很多早期文章将 Triton 的”Dynamic Batching”等同于后续的”Continuous Batching”,但实际上 Triton 的 Dynamic Batching 仍是请求级的——它在时间窗口内收集请求拼批,但一旦批开始执行,内部的请求就不再变化。
❌ 误读 2:“Batch 越大,延迟越低”
纠偏:Batch 越大,吞吐越高,但单请求延迟通常不降反升。
- 增大 batch → GPU 并行度提升 → 总吞吐(tokens/s)上升。
- 但更大的 batch 意味着每个请求在 GPU 上排队等更多并行任务 → 单请求延迟(特别是 decode 阶段的 TPOT)可能增加。
- Dynamic Batching 的精妙之处在于:不做一刀切的大 batch,而是根据实时负载自适应调整 batch 大小,在吞吐和延迟之间寻找最优解。
❌ 误读 3:“有了 Dynamic Batching 就不需要关心模型优化了”
纠偏:Dynamic Batching 是系统层优化,不能替代模型层优化。
- 模型层:量化(INT8/INT4)、剪枝、知识蒸馏、MQA/GQA 减少 KV cache → 直接降低每个请求的资源占用。
- 系统层:Dynamic Batching、PagedAttention、kernel fusion → 提升资源利用效率。
- 两者是乘法关系:模型越轻量,同样的 batch 容量下能放更多请求;batching 越高效,模型优化带来的单位收益被放大。
❌ 误读 4:“Prefill 和 Decode 应该总是一起做 batching”
纠偏:Prefill 和 Decode 的计算特征截然不同,混在一起 batching 会互相干扰。
- Prefill 计算密集(高 arithmetic intensity),可以充分利用 GPU 的算力。
- Decode 访存密集(低 arithmetic intensity),瓶颈在 HBM 带宽。
- 一个长 prompt 的 prefill 会阻塞同 batch 中正在 decode 的请求(增加其 TPOT),反之 decode 的低算力利用拉低了 prefill 的效率。
- 2024 年以来的研究趋势(Splitwise、DistServe 等)正是将两者分离到不同实例上,各自做最优的 batching 策略。
学习路径
Level 0: 理解 LLM 推理基本流程
└─ 什么是 prefill、什么是 decode、什么是 KV cache
└─ 推荐: 任意一篇 "LLM Inference Explained" 的博客
Level 1: 理解 batching 的基本概念
└─ 为什么需要 batching(GPU 并行计算 vs 串行请求)
└─ 静态批处理的问题(padding 浪费、bubble)
└─ 推荐: NVIDIA Triton 官方文档中的 Dynamic Batching 章节
Level 2: 阅读核心论文
└─ Orca (OSDI'22): "Orca: A Distributed Serving System for Transformer-Based Generative Models"
└─ 理解 iteration-level scheduling 的设计动机和实现
└─ vLLM (SOSP'23): "Efficient Memory Management for Large Language Model Serving with PagedAttention"
└─ 理解 PagedAttention 如何支撑灵活的 dynamic batching
Level 3: 读源码 / 动手实验
└─ vLLM 源码中的 `Scheduler` 类 → 理解 waiting/running/swap 状态机
└─ SGLang 源码中的 `Scheduler` → 对比不同调度策略
└─ 用 vLLM 本地部署一个模型,调整 `max_num_seqs`、`max_num_batched_tokens` 观察延迟/吞吐变化
Level 4: 关注前沿
└─ Prefill-Decode 分离 (Splitwise, DistServe)
└─ Chunked Prefill 的调度策略
└─ 多模态推理中的 batching(图像/视频 token 与文本 token 的异构调度)
└─ Speculative Decoding 与 batching 的交互
一句话总结
Dynamic Batching 是 LLM 推理引擎的灵魂调度策略——从请求级拼批到迭代级连续批处理再到 Prefill-Decode 分离,其演进方向始终是”让 GPU 每一纳秒都在做有效计算”,是推理成本曲线下降的关键推手。
延伸阅读与来源
- Orca: A Distributed Serving System for Transformer-Based Generative Models — Yu et al., OSDI 2022. (连续批处理 / iteration-level scheduling 的奠基论文)
- Efficient Memory Management for Large Language Model Serving with PagedAttention — Kwon et al., SOSP 2023. (vLLM / PagedAttention 论文)
- SGLang: Efficient Execution of Structured Language Model Programs — Zheng et al., 2024. (RadixAttention)