阶段三 · 进入引擎核心

Chapter 05 · 调度与吞吐:batching、continuous batching、paged attention

你已经知道单个请求如何活着,现在问题变成:一批请求同时进来时,系统怎么排队、怎么组 batch、怎么尽量把 GPU 吃满、又怎么避免缓存管理失控。这一章就是从单请求视角正式切到多请求系统视角。

时长 4 天
难度 L3 进阶
先修
调度策略 continuous batching paged attention

章节导读

在线推理服务最难的地方,往往不是单次执行,而是“很多不同长度、不同状态、不同优先级的请求一起进来时,怎样不把硬件浪费掉”。这一章讨论的 batching、continuous batching 和 paged attention,本质上都在回答这个问题。

这一章的核心问题

如何在吞吐、延迟、显存和公平性之间做调度权衡。

你要形成的直觉

批处理不是把请求“攒一攒”这么简单,而是和请求状态机、缓存管理一起设计。

阅读方式建议

先抓住“请求何时进入 batch、何时退出、缓存何时分配与回收”这三条主线。

本章目标

  • 理解为什么 batch 是推理引擎提升设备利用率的核心手段。
  • 知道固定 batch 与 continuous batching 的差异,以及它们分别更像什么场景。
  • 理解 paged attention 主要在解决缓存组织和内存管理问题。
  • 学会用吞吐、延迟、公平性和显存占用一起评价调度策略。

前置知识

必须知道

  • 请求生命周期和 KV Cache 基本概念。
  • 首 token latency、总 latency、吞吐是不同指标。
  • 高并发会让缓存压力和队列行为变得关键。

建议知道

  • GPU 需要足够多并行工作才能高效运行。
  • 请求长度差异会让任务执行时间差很多。
  • 内存碎片化会让“看起来有空间”却不好分配。

本章重点不是

  • 不是记住每个框架 API。
  • 不是只看某一条 benchmark 数字。
  • 而是理解多请求服务为什么一定要有调度策略。

正文主线

1. 为什么 batch 是推理引擎的核心工具

单个请求往往无法充分利用 GPU 资源,所以系统会尽量把多个请求组织在一起执行。这就是 batch 的基本动机:提高硬件利用率,把更多 token 处理放进同一个执行窗口里。

但在线服务不是离线训练。离线场景里你可以等一批样本凑齐再统一跑,在线服务里用户在等待响应。于是 batch 从一开始就不是纯粹的“吞吐工具”,而是一个需要在等待时间和利用率之间平衡的调度工具。

2. 固定 batch 为什么不够

传统固定 batch 的思路,是等一批请求凑好后一起执行,跑完再接下一批。这在离线处理里很自然,但在线场景中会带来明显空档:有的请求已经完成,有的新请求却还在门口等下一轮开车。设备利用率和等待时间都会受到影响。

更麻烦的是,请求长度往往不同。有的 prompt 很短,有的输出很长。如果所有请求都被绑在固定批次里,短请求会被长请求拖着走,系统的“平均效率”就会掩盖很多局部浪费。

3. Continuous batching 改变了什么

continuous batching 的核心思想,是让系统尽量持续吸收新请求进入运行窗口,而不是等整批完成再开下一批。这样做可以减少批次之间的空洞,提高在线服务中的设备利用率。

但收益的另一面是复杂度上升。系统需要持续判断哪些请求在 decode、哪些刚完成 prefill、哪些该结束回收缓存、哪些新请求可以插入。它本质上要求调度器随时面对“一批状态不同的活跃请求”。

4. Paged attention 为什么和调度紧密相关

如果 KV Cache 只能按大块连续空间管理,那么高并发、长上下文、频繁插入和释放请求时,很容易出现碎片化和分配压力。paged attention 用分页思路组织缓存,目的就是让缓存管理更灵活、浪费更小、请求共存更可控。

这意味着 paged attention 不只是“一个 attention 优化技巧”,更是调度和内存管理的基础设施。它让调度器在面对动态请求流时,有更现实的缓存组织手段。

5. 怎样评价一个调度策略是否合理

只看吞吐不够。一个调度策略至少要同时接受四种审视:吞吐是否提高、延迟是否可接受、显存是否可控、请求之间是否公平。如果一个系统为了吞吐让短请求全部排长队,对某些在线产品来说就可能完全不可用。

后面你看框架对比时,应该带着这些问题去问:它更偏吞吐还是更偏时延?它对长短请求混跑友好吗?它的缓存组织能不能支撑动态调度?

6. 一旦有优先级和 SLA,调度就不只是效率题

真实产品里,请求往往不是完全平等的。交互式请求、内部高优工单、批量离线任务,容忍的等待时间都不同。调度器如果只按“尽量把 GPU 填满”设计,就可能把最需要快速响应的请求也拖进长队列。

这意味着调度策略最终要同时服务两种目标:一类是硬件利用率,一类是产品侧的服务等级要求。很多框架和平台能力的差异,也正体现在是否允许你把这种业务约束带进调度器。

工程判断

先判断负载是不是“在线型”

如果用户在等结果,固定 batch 的很多简化假设就不再成立,你更需要关注等待时间和批次空洞。

  • 在线请求优先看首包和平均等待。
  • 离线任务才更容易接受攒批等待。
  • 这会直接决定你是否值得上 continuous batching。

先看长度分布,再谈 batch 效率

当请求长度差异很大时,平均吞吐数字常常掩盖短请求被长请求拖慢的问题。

  • 先分短 prompt / 长 prompt、短输出 / 长输出。
  • 再看混跑下的等待时间是否失控。
  • 这是判断公平性问题的最直接抓手。

缓存组织决定调度天花板

如果缓存分配和回收太僵硬,再好的调度策略也很难在动态请求流里稳定落地。

  • 先看 KV Cache 的组织方式。
  • 再看是否支持动态插入和释放。
  • paged attention 的价值正是在这里显现。

场景拆解

混跑 公平性 动作

短问答和长报告生成放在同一服务里

如果系统一味追求大 batch,短问答请求可能会被长报告任务拖住,用户会直接感觉“怎么问个小问题也这么慢”。

  • 先按长度分布观察等待时间。
  • 必要时分队列或引入优先级。
  • 别让总体吞吐掩盖体验恶化。
高优先级 SLA 动作

客服机器人请求需要明显快于后台批处理

这时调度器就不能只按统一 FIFO 思路工作,而要把业务优先级带入排队和插队策略中。

  • 先定义哪些请求必须抢响应时间。
  • 再决定是否允许批处理让位。
  • 这是“调度服务产品目标”的典型例子。

图解实验室

把固定 batch 和 continuous batching 放到同一视图里,差异会比文字描述更直接。

调度与批处理关系图

左边是整批进入、整批退出;右边是动态插入、动态退出。两者真正的分水岭,在于状态和缓存能不能跟上。

固定 batch

更像一班一班发车,适合规则负载,但在线场景容易形成空档。

攒够一批请求 新请求先排队,等到批次满足条件再统一进入。
整批执行 同一批次一起跑,短请求也会被长请求绑住。
整批退出 本批结束后,下一批请求才能整体接上。

Continuous batching

更像一条持续吸收请求的流水线,吞吐更高,但调度状态明显更复杂。

活跃请求窗口 系统持续维护一组正在 prefill / decode 的请求。
动态插入新请求 有空位时,新的请求可以在运行过程中进入。
随完成随退出 请求一旦结束就回收位置和缓存,不等整批一起收尾。
KV Cache 请求能否长期共存,取决于缓存能不能被持续分配、复用和回收。
Paged attention 用更灵活的分页组织撑住动态调度,否则 continuous batching 很容易被内存管理拖垮。

关键表格与结论

机制 主要目标 带来的收益 代价 / 难点
固定 batch 把请求聚合成统一执行单元 实现简单,适合离线或规则负载 在线服务空档多、等待成本高
continuous batching 持续吸收新请求进入执行窗口 在线吞吐更高,利用率更好 调度状态更复杂
paged attention 更灵活地组织 KV Cache 减少碎片化和内存浪费 需要更精细的缓存管理设计

结论 1

吞吐优化的前提是状态管理做得住。没有稳定的请求状态和缓存组织,调度策略很难成立。

结论 2

一个好的调度策略不只是“让 GPU 更忙”,还要回答“让谁先等、谁先走、代价是否可接受”。

动手任务

任务 1:写一张“固定 batch vs continuous batching”对比表

至少比较吞吐、等待时间、实现复杂度、适用场景。最低完成标准是:你能说明为什么在线服务更偏好后者。

任务 2:列出三个让调度变难的请求特征

例如长上下文、长输出、高优先级请求。最低完成标准是:每条都要写出它为什么会增加调度难度。

任务 3:解释 paged attention 更像在解决什么问题

最低完成标准是:答案里必须出现“缓存组织”或“内存管理”,而不是只说“更快”。

任务 4:为一个聊天服务写一段调度目标说明

要同时提到首 token latency、吞吐、公平性三件事。最低完成标准是:不是只写“尽量快”。

阶段产出

产出 1

一张两类 batching 方案对比表。

产出 2

一份调度难点清单。

产出 3

一段关于 paged attention 作用的工程化解释。

自测问题

  1. 1. 为什么在线推理里的 batching 不能简单照搬离线批处理思路?

    如果你能把等待时间和请求长度差异讲出来,说明理解到位。

  2. 2. continuous batching 比固定 batch 多出来的复杂度主要在哪?

    关键不在 API,而在持续面对状态不同的活跃请求。

  3. 3. paged attention 为什么能和调度问题连在一起讨论?

    如果你能把答案说到“缓存更灵活,调度才更现实”,就已经抓住重点。

  4. 4. 吞吐提升和延迟变差为什么可能同时发生?

    这是所有调度策略都绕不开的权衡。

推荐资料

论文 / 技术文章

源码入口

  • Source vllm-project/vllm

    适合继续找调度器、请求状态和缓存布局相关实现。

  • sgl-project/sglang

    适合比较另一条高性能 serving 路线在调度和能力暴露上的取舍。

实践建议

  • Practice vLLM 文档首页

    后面结合框架实战时,再回来看 continuous batching、serving 和 benchmark 模块会更有效率。

常见误区

误区 1:把 batch 理解成“攒够一堆请求再跑”这么简单

在线服务里的 batch 是调度系统的一部分,不只是聚合操作。

误区 2:觉得 paged attention 只是新的注意力名字

它更关键的价值在缓存组织和内存管理,而这正是服务系统的核心痛点。

误区 3:只看吞吐不看等待时间和公平性

对在线产品来说,这会直接破坏真实用户体验。

下一章衔接

现在你已经知道系统为什么要调度、怎样组 batch、缓存管理为什么重要。下一章会把这套系统问题往下继续压成“优化工具箱”:量化、算子、编译、内存和通信各自在解决什么瓶颈。