17 批处理层
17.1 连续批次
连续批处理是把单机吞吐拉高数倍的核心机制,原理是不让 GPU 空等。传统静态批处理把若干请求凑成一批一起算,必须等这批里最慢的算完才能整批退出;而生成任务的长度差异极大,有人要 20 个字,有人要 2000 个字,短请求算完之后它的位置一直空着等长请求,GPU 大量空转。连续批处理(continuous batching,也叫 in-flight batching)以 token 为粒度调度:每完成一步生成,就检查哪些请求结束了,立刻踢出去、把排队的新请求填进来,批次的成员每一步都可能变化。Orca 提出的迭代级调度是这一思路的源头,现代主流引擎都采用类似机制。核
要补一句代价:整体填充率提高不意味着每个请求更快。调度器为了吞吐不断扩大批次,新到请求可能排队更久,正在生成的请求也可能经历更高的出字间隔。系统目标不是让每个请求独占最快,而是在首字与出字约束内完成尽可能多的有效请求。
17.2 排队模型
并发上限不是一个固定数字,它随请求的上下文长度动态变化。这一点在合同谈判里经常出事:客户按峰值并发签 SLA,供应方按平均上下文算产能,上线后长上下文请求一多就爆。调度器每一步都在做一次决策:显存里还剩多少 KV 块,能不能再放进来一个请求;放不下就排队,排队时间直接体现为首字延迟上升。显存吃紧到一定程度,调度器还会主动把某些正在跑的请求踢出去(抢占),把它们的 KV 丢弃或换出,腾出空间给别人,被踢的请求之后要重新计算,这就是抢占的代价。
长 prefill 干扰 decode 的问题有专门的解法:分块预填充把长提示词切成较小块,在块之间穿插 decode,缓解吞吐与逐 token 延迟的冲突。核块不是越小越好:小块增加调度和内核启动开销,大块重新形成阻塞,最佳块大小取决于模型、卡、长度分布和服务目标,生产配置应在真实长度分布上找约束内的前沿,不能照抄论文参数。
17.3 调度资源
调度器表面上在选请求,实际上同时分配四类稀缺资源:迭代中的 token 槽位、显存中的 KV 块、prefill 与 decode 的执行时间、用户可接受的等待预算。显存不足时有四个动作可选:拒绝新请求、抢占低优先级任务、把 KV 卸载到内存、回收后重新计算。每个动作把成本转给不同对象:拒绝伤成功率,抢占伤低优先级延迟,卸载耗互联,重算耗 GPU。利用率最高不是完整目标:把显存压到没有余量,突发流量会触发频繁抢占和重算,短期利用率上升,P99 延迟与故障恢复却恶化。
17.4 优先策略
同一批产能上跑多个客户时,调度策略就是商务条款的技术实现。
| 策略 | 机制 | 适合的商业场景 |
|---|---|---|
| 先到先服务 | 按到达顺序准入 | 单一客户,无差别 SLA;缺点是长 prefill 造成队头阻塞 |
| 优先级抢占 | 高优请求可挤掉低优 | 分档定价,高价档保延迟;需要老化保护防止低优饿死 |
| 配额隔离 | 按租户预留 KV 与批位 | 多租户,防止互相踩踏 |
| 分时调度 | 按时段划分产能归属 | 白天供 A 区,夜间供 B 区 |
| 降级路由 | 过载时转发到低配集群或小模型 | 保可用性,牺牲质量 |
录音里提到的白天供中国、夜间供欧美的做法,录在技术上就是分时调度加路由层的地域切换。它成立的前提是两个市场的高峰时段错开,且两边的 SLA 都能被满足,第 25.3 节会算这个套利的经济价值。抢占也不是一个布尔能力:暂停一个 decode 请求,KV 留在显存释放不了容量,卸载到内存要付传输,直接丢弃则恢复时要重新 prefill,调度器要按要释放的资源和预计恢复成本选择动作。
17.5 验收方法
缓存与批处理的验收至少做六组实验:相同长度不同并发,看 KV 与吞吐;相同并发逐步加长上下文,看容量曲线;混合长短请求,看队头阻塞;共享前缀与随机提示词对照,看实际命中;取消和超时风暴,查回收;持续运行反复装卸请求,查碎片和泄漏。每组同时记录首字延迟、出字间隔、有效吞吐、KV 字节、碎片、命中、淘汰、抢占、卸载和重算次数。实验要分冷缓存和热缓存两组:热缓存描述稳态局部性,冷缓存描述首次请求,两者都真实,适用场景不同。展示最好吞吐之前,先给冷缓存、取消风暴和持续运行的结果。
修订记录
| 日期 | 改了什么 | 为什么 | 谁 |
|---|---|---|---|
| 2026-08-04 | 按章导入,正文与插图保持原样 | 原稿结构清晰,重写反而损失信息 | 工程 |