请求一起进来,谁应该先走?

区分连续批处理、分块 prefill 和分页缓存,在长短请求中验证调度取舍。

第 07 单元 · 约 80 分钟(含练习) · 产出:调度对照、失败反例与原始 trace

从哪里接上:第 06 课的生成状态

长请求进来以后,短请求为什么也在等?

你已经让模型装进显存,单条请求也能正常生成。下一步把服务交给多人使用:A 的文字刚开始输出,L 带着很长的输入进入队列,S 随后发来一句短问题。监控上的 tokens/s 没有明显下降,A 却停顿了很久,S 的首字也迟迟没有出现。你现在要解释的是请求之间如何争用一次执行机会,而不是重新计算模型能不能装下。

prefill 处理输入,decode 利用已有状态继续生成。一个调度周期可以为新请求执行 prefill,也可以让已有请求生成下一步;设备计算、KV 容量、token 预算和等待策略共同限制这个决定。先后次序会改变每个用户看到的时间线。总输出数相同,等待分布仍可以相差很大。

先记住观察对象:A 的首 token 已经到达,后来的长 prefill 会影响 A 的后续 ITL,不能倒改它已经发生的 TTFT。S 尚未得到首字,入队到首 token 的等待属于 S 的 TTFT。把两者混成“生成变慢”,就很难判断该验证哪种机制。

三种机制,各解决一个不同问题

连续批处理在请求完成后允许其他请求加入后续批次,不必等整批最长的请求结束。它减少空出来的执行位置,但不自动保证短请求优先,也不承诺所有用户的延迟都会下降。一个位置空出来后,仍需要决定接纳哪个请求,以及剩余 KV 是否足够。

分块 prefill把长输入拆成多次可调度的计算,为 decode 留出间隔。chunk 太大,已有请求可能等待更久;chunk 太小,长输入完成需要更多周期,额外提交和调度开销也可能增多。改变 token budget 是改变时间分配,不能只盯一个吞吐数字。

分页 KV改变缓存的分配和寻址,减少大块连续预留造成的浪费,并可支持符合条件的共享。它不是把 prefill 计算凭空省掉,也不是直接把 FIFO 队列变成短作业优先。第 06 课的张量容量账仍要保留;实际块大小、共享前提、抢占与重算也应记录。

先用一条可手算的时间线比较

离线实验有一个刻意简单的虚拟设备:一个 prefill token 花 1ms,一次 decode batch 花 1ms,每次提交额外 0.25ms;prefill 完成时发出首 token。decode batch 的时间在此模型中不随活跃请求数变化。没有真实 GPU、KV 容量、抢占或通信。这里的数字用来隔离调度次序,不能换成某个引擎的性能承诺。

mixed 固定输入:到达时间属于每条请求,不因排队改变
请求到达输入 tokens输出 tokens
A0ms212
L2ms122
S4ms14

先看“完整 prefill 优先”,命令中的名字是 fcfs:等待 prefill 按到达先后处理,有等待项就先完整执行;之后再 decode 活跃请求。这里 FIFO 描述 prefill 队列次序,并不是把每条请求从头到尾串行执行。

首 token 和下一次输出是两个时间点

  1. A 从 0 到 2.25ms 完成 prefill,首 token 到达,因此 A 的 TTFT=2.25ms。
  2. L 已在 2ms 到达,从 2.25 到 14.50ms 执行完整 prefill。L 的 TTFT=14.50−2=12.50ms。
  3. S 从 14.50 到 15.75ms 执行,TTFT=15.75−4=11.75ms。
  4. 第一次 decode batch 到 17ms 结束,A 得到第二个 token。A 的第一个 ITL=17−2.25=14.75ms。
完整 prefill 阻塞与分块插入 decode 的时间线完整策略在 A 首字后执行长 L 和短 S 的 prefill,A 第二字到17毫秒。分块策略先decode,再执行L的2token块,使A最大间隔缩至3.5毫秒,但L与S首字更晚。完整 prefill 优先:A 首字后,一大段执行机会给 LL 的完整 prefill · 12.25msA 首字 2.25ms → A 第二字 17ms;中间间隔 14.75mschunk=2:每次让 decode 先走,再执行最多 2 个 prefill tokens绿色:decode batch 1.25ms;黄色:L 的一个块 2.25ms。图示开头几个周期。
图 07.1 · 按同一时间比例绘制的教学开头片段。第二种策略插入更多 decode,完整 trace 保留每个 token 时间;图不推导真实 GPU 利用率。

现在使用 chunk=2:先为活跃 decode 提交一个 batch,再执行队首 prefill 的最多 2 tokens。A 的最长间隔变为 1.25+2.25=3.50ms;它的 TTFT 仍为 2.25ms。L 和 S 仍按 FIFO 等待,而 L 被拆成更多轮次,因此它们的首字更晚。不能从 A 的改善推断所有请求都改善。

把预测和真实模拟输出放在一起

下载完整离线实验 ZIP,解压进入 infra-lab。先写下你预测改善的指标,再运行;无需 GPU 或 pip。实验说明包含规则、故障开关与验收,原始调度输入可以逐条查看。

python3 simulate.py --trace mixed --policy both --chunk 2 --output runs/mixed.json
python3 simulate.py --trace prefill-only --policy both --chunk 2 --output runs/prefill-only.json
上述命令的实际模拟结果,非 GPU 基准
mixed 策略A 最大 ITLL TTFTS TTFT全批结束
fcfs14.75ms12.50ms11.75ms29.50ms
chunk=23.50ms21.25ms21.75ms30.75ms

反例也要保留。prefill-only 只有一个输入 12、输出 1 的请求:完整策略为 12+0.25=12.25ms;chunk=2 提交六次,为 12+6×0.25=13.50ms。没有已有 decode 需要保护,切块在这个模型中只增加提交成本。将 --overhead-ms 0 加到该命令后,两种策略都是 12ms。这给出了可复测的解释,而不是一句“分块总是更慢”。

打开输出 JSON,找到 A 的 tokenTimesMs 与执行 events。用相邻时刻相减重算最大 ITL,再检查 S 的 arrival、firstToken 和 TTFT。若打印表与原始时序对不上,先修日志和统计,不要急着调参数。

从模拟迁移到真实引擎,还缺哪些证据?

真实 GPU 上 prefill 与 decode 的时间受 batch、shape、精度和 kernel 影响,并不按本实验的固定成本运行。引擎还可能做前缀缓存、抢占与重算;容量紧张时,请求即便有执行优先级,也未必能被接纳。分页、分块和优先级共同变化时,必须分开记录配置和缓存状态,不能用本模拟的排名直接选生产参数。

时序不对时,先补什么
现象需要的证据一项受控改动
首字很晚原到达、入队、开始 prefill、首输出固定长度,仅改 token budget
输出中途停顿后续输出事件、抢占、长 prefill固定负载,仅开启或关闭分块
并发升高后尾延迟突增KV 块水位、接纳量、重算计数保留每次失败,仅降低并发上限

若流式事件一次携带多个 token,事件间隔与真正每 token 的间隔不等价。报告应写清引擎和客户端的定义,并同时记录输出 token 数与结束原因。本课一事件一 token 的假设不能默默沿用到推测解码场景。

交付一份含反例的调度对照

  1. 重算 mixed。提交三条请求的到达、首字、结束和 A 最大 ITL;用事件解释 A 为什么改善、S 为什么变差。
  2. 检验反例。对 prefill-only 分别设 overhead=0.25 与 0。保留预测、输出和六次提交的计数,区分调度次序与提交开销。
  3. 陌生负载。先预测 unseen 中 U2 的首字和 U1 的最长停顿,再用 python3 simulate.py --trace unseen --policy both --chunk 4 --output runs/unseen.json 验证。写出一个改变之后需要重新排名的条件。
参考与完成标准

mixed 的关键数值见上表;A 第一字已经发生,因此两策略 A TTFT 相同。单请求零提交开销均为 12ms,非零时 12.25 对 13.50ms。陌生负载没有沿用 mixed 的答案:应从新 arrival/token 序列重新计算,保留原始 JSON。长度比例、到达过程、KV 容量、优先级或提交成本改变,都构成复测触发条件。

完成标准:定义完整;至少一项逐 token 复算;至少一个失败反例;能说出模拟未覆盖的两个真实机制;结论限定到当前 trace。只写“chunk 更好”未通过。

mixed 的结果支持哪项结论?

带着时间线读原始资料

vLLM · Optimization and Tuning:找到 chunked prefill、decode 优先和 token budget。读前预测缩小预算会牺牲什么;读后用本课的 A/L/S 指出真实实现还需核对的版本和容量条件。PagedAttention 论文:重点读缓存碎片与共享的机制,用一段话解释为什么它与调度次序不是同一个问题。核对日期 2026-10-04;参数以安装版本为准。

下一步:如何把这些时序变成一个可接受的运行点?

你会解释某条请求为何等待,但不能仅凭一个 trace 推断服务值得上线。第 08 课会固定实验协议,保留全部失败,再同时验收质量和时延;最后在可行档位里比较合格请求的成本。

留下本课的产出

本课产出:调度对照、失败反例与原始 trace。写下条件、证据、结果和仍不确定的事。保存不代表自动通过,下面的状态由你按验收条件自检。

记录只保存在当前浏览器。

按验收条件自检