博客
文章系列日历
归档关于搜索

鄂ICP备19019526号

© 2026 博客

  1. 文章
  2. LLM 推理调度的延迟公平性工程 2026:从 WFQ、抢占到多 SLO 的生产闭环

LLM 推理调度的延迟公平性工程 2026:从 WFQ、抢占到多 SLO 的生产闭环

2026年7月22日·约 24 分钟·7087 字·2 次阅读
AI 原生架构
LLM 推理调度的延迟公平性工程 2026:从 WFQ、抢占到多 SLO 的生产闭环

目录

  • 一、问题的提出:从一次 5% 的 TTFT p99 漂移开始
  • 二、形式化:调度器四元组 (R, S, Q, D)
  • 三、主体一:公平排队——从 FIFO 到 WFQ/DWRR 的工程演进
  • 四、主体二:抢占语义——Cooperative 与 Non-Cooperative 的 KV 缓存鸿沟
  • 五、主体三:多 SLO 分层调度——Tiered Scheduling 的工程真相
  • 六、统一视角:调度器 = 拥塞控制 + 资源分配双闭环
  • 七、对工程实践的推论:六条可执行项
  • 八、讨论与对比:与连续批处理 / 自适应 batch 的边界
  • 九、给 LLM 推理平台架构师的清单
  • 参考文献

LLM 推理服务的请求调度与延迟公平性工程 2026:从公平排队、抢占语义到多 SLO 分层调度的生产闭环

当 LLM 推理的瓶颈从 KV 内存转移到调度器公平性,我们看到 TTFT p99 在多租户混合负载下漂移 5%,长尾请求被短请求频繁插队饿死;本文从 WFQ 公平排队、协作/非协作抢占、多 SLO 分层队列三方面拆解生产级推理调度器的工程真相。

一、问题的提出:从一次 5% 的 TTFT p99 漂移开始

2026 年第一季度,某中等规模的 LLM 推理平台(80 块 H100,单实例最大 QPS 3200)在一次内部容量复盘会议上,运维团队汇报了一件看似微小却极其棘手的事:在最近 14 天的滚动窗口里,TTFT p99(Time To First Token 第 99 百分位)从基线的 240ms 漂移到了 252ms,相对涨幅 5%,而 P50、p95 均无显著变化,token/s 总吞吐也没有下降。换句话说,GPU 利用率曲线、显存占用曲线、KV 命中率曲线三项传统告警指标全部正常,但长尾请求的尾延迟却在静悄悄劣化。

第一反应是"模型体积变大导致 prefill 变慢",但回滚对比显示,模型版本、量化方案、调度策略都没有变更,Grafana 上唯一异常的是调度器队列长度指标 scheduler.waiting_queue_len 的方差在 14 天内上升了 1.8 倍——均值没变,但尾部的偶尔尖刺开始浮现。这种"均值不变、长尾恶化"的特征是典型的调度器不公平信号:不是算力不够,而是排队策略让某些请求被频繁插队或反插队。

进一步排查发现三件事。第一,平台从单租户单队列升级为多租户共享 GPU 池后,租户优先级路由启用了,但租户之间的队列公平性未启用——高优先级租户的突发流量持续占据 worker slot,低优先级租户的请求被推迟到下一个 epoch 才被调度。第二,平台支持prefill-decode 分离架构(即 Prefill 和 Decode 分别在不同 pod 上执行,中间通过 RDMA 传 KV 缓存),prefill pod 的 KV cache 写入延迟方差变高,导致 decode pod 的等待时间出现"光斑式"长尾。第三,SLO 配置错配:同一调度器实例内同时承载交互式(目标 TTFT ≤300ms)和批处理式(目标 TTFT ≤2s,注重吞吐)两类请求,二者被错误地放入同一个 FIFO 队列,长请求(输入 4k tokens)与短请求(输入 80 tokens)相互排挤,导致前者偶尔饿死、后者被插队。

这三件事都不是"算力问题",而是调度器层的工程问题。本文的核心主张是:2026 年的 LLM 推理系统工程重心已经从"压榨单请求时延"转向"调度器公平性"——多租户共享 GPU 池里,5% 的 TTFT p99 漂移绝大多数是优先级反转、长尾饿死或 SLO 错配的征兆,而非算力不足。围绕这个主张,本文从三方面展开:其一,公平排队(Weighted Fair Queueing / Deficit Weighted Round Robin)的工程实现;其二,抢占语义(Cooperative vs Non-Cooperative Preemption)对 KV cache 的破坏性差异;其三,多 SLO 分层调度(Tiered Scheduling)在 vLLM、TGI、SGLang 三大开源推理框架中的落地形态。

需要预告的是,本文的工程论断建立在三大开源推理框架(vLLM v0.7+, TGI v3.0+, SGLang v0.3+)的源码阅读与可复现实验之上,对生产真实负载的覆盖未达 100%——具体来说,我们在三种典型混合负载(交互式聊天 / 长文档摘要 / 批量 embedding)上做了对比实验,但对更细分的 workload pattern(如 RAG 重排序、流式 agent 多步推理)覆盖不足,这些是后续工作。本文所有未明确指出的厂商数据均来自公开 README 或论文,截至 2026-07 未有公开的完整 SLI/SLO 行业基准,相关阈值仍待业内进一步规范。

二、形式化:调度器四元组 (R, S, Q, D)

为了后续讨论的严谨性,我们先把推理请求从进入到完成的过程抽象成一个调度器四元组 (R,S,Q,D)(R, S, Q, D)(R,S,Q,D)。

R(Request, 请求) —— 一个 LLM 推理请求 rrr 由若干属性描述:r=(prompt_len,max_tokens,stream,slo_class,tenant_id,arrival_ts)r = (\text{prompt\_len}, \text{max\_tokens}, \text{stream}, \text{slo\_class}, \text{tenant\_id}, \text{arrival\_ts})r=(prompt_len,max_tokens,stream,slo_class,tenant_id,arrival_ts)。其中 prompt_len\text{prompt\_len}prompt_len 决定 prefill 的算力消耗,max_tokens\text{max\_tokens}max_tokens 决定 decode 的步数,stream\text{stream}stream 标记是否走 SSE 流式输出,slo_class∈{interactive,batch,best-effort}\text{slo\_class} \in \{\text{interactive}, \text{batch}, \text{best-effort}\}slo_class∈{interactive,batch,best-effort} 是租户级 SLO 标签,tenant_id\text{tenant\_id}tenant_id 用于多租户隔离的额度计量。

S(Scheduler, 调度器) —— 调度器 sss 在每个决策 epoch(vLLM 中是 engine step,TGI 中是 batch iteration)从队列里选取最多 BBB 个请求送入 worker pool。BBB 由 worker 数 ×\times× max_batch_size\text{max\_batch\_size}max_batch_size 决定,但实际 batching 还受 prefill-decode 分离策略影响。调度器的状态包含 s.policy∈{FIFO,WFQ,DWRR,tiered}s.\text{policy} \in \{\text{FIFO}, \text{WFQ}, \text{DWRR}, \text{tiered}\}s.policy∈{FIFO,WFQ,DWRR,tiered},以及各类内部计数(如每个租户的待处理 token 数、每个 SLO class 的 SLA 达成计数器)。

Q(Queue, 队列) —— 队列 qqq 是请求按调度策略排序的抽象,实际实现上可能是多个 FIFO 子队列 + 一个排序器(sort scheduler in vLLM v0.7+)。队列容量 q.capq.\text{cap}q.cap 决定了背压(backpressure)的上限,超容的请求被立即 reject 或排队到 external queue(前者适合边缘网关,后者适合核心调度器)。

D(Degradation, 降级) —— 降级策略 ddd 包含三种语义:抢占(preemption)、降级(demotion)、拒绝(rejection)。三者代价递增:preemption 暂停低优先级请求释放资源给高优先级,需配合 KV 缓存的回写策略;demotion 把请求从快车道移到慢车道(如从交互队列移到批队列),只调整排队位置不破坏已计算结果;rejection 立即返回 503 + Retry-After,适合过载保护。

三者合起来,调度器每一轮的工作可表达为:

Schedule(s,q,d)=argmaxr∈candidates(q,d)∑iwi⋅scorei(r)\text{Schedule}(s, q, d) = \mathrm{argmax}_{r \in \text{candidates}(q, d)} \sum_{i} w_i \cdot \text{score}_i(r)Schedule(s,q,d)=argmaxr∈candidates(q,d)​∑i​wi​⋅scorei​(r)

其中 wiw_iwi​ 是策略权重,scorei(r)\text{score}_i(r)scorei​(r) 是各评分维度(如 fairness score、priority score、SLA penalty score)。后续三节我们逐步展开 scorei\text{score}_iscorei​ 的具体实现。

需要强调的是,调度器与 microbatch scheduler 是不同层——本文讨论的是请求级调度(request-level scheduling),即哪个请求被送入 worker pool 的下一轮,而 vLLM 的 ContinuousBatchingScheduler(参见 pitfall #82 同主题文章 id=382)讨论的是token 级调度(token-level batching)。二者通过"请求队列 → token 序列"两层映射协作,但工程指标体系与瓶颈识别方式不同:token 级调度关注 iteration time 与 batch token count,请求级调度关注 waiting time 与 queue depth。

三、主体一:公平排队——从 FIFO 到 WFQ/DWRR 的工程演进

最早的推理调度器基本都是 FIFO:先来先服务,实现简单,但长请求频繁饿死短请求(head-of-line blocking)。具体来说,一个 4k tokens 的 prompt 占住 prefill slot 数十毫秒,后续到达的 80 token 短请求全部堵在队列里,TTFT p99 取决于"队首长请求的 prefill 时间 + 后续 decode 时间",而非"理想均值"。

DRR(Deficit Round Robin)与 WFQ(Weighted Fair Queueing)的引入是为了打破 head-of-line blocking。DRR 的核心思想是为每个租户/类分配一个"配额(quantum)",每轮按配额发送请求,本轮未用完的配额累计到下一轮("deficit"语义)。这能在多租户场景下保证每个租户至少有一定带宽,但粒度仍较粗——只在请求维度分配,不考虑请求的算力消耗。实际生产中,一个 80 token 请求和一个 4k token 请求的算力消耗相差 50 倍,如果按"请求数"分配,显然对短请求不公平。

WFQ(Weighted Fair Queueing) 把公平性的粒度从"请求数"下沉到"虚拟时间( virtual finish time)"。具体来说,每个请求 rrr 到达队列时,根据 r.weightr.\text{weight}r.weight 估算一个虚拟完成时间 F(r)F(r)F(r),队列内按 F(r)F(r)F(r) 升序排序,调度器优先服务 F(r)F(r)F(r) 最小的请求。理论上,WFG 能保证:在任意时间窗口内,任意两个租户的实际服务量之比不超过其权重之比的 1 倍——这就是著名的 GPS (Generalized Processor Sharing) 公平性近似。

然而 WFQ 在 LLM 推理场景下有三个工程难题:

  1. 权重的"算力等价性"难定义。80 token 的 decode 一轮只需 ~1ms,4k token 的 prefill 一轮需 ~50ms,如果按"代价值"做权重,需要维护一个"代价值表"——但不同模型、不同量化、不同 prompt 长度下,这个表不可枚举。工程上的妥协是采用 prompt length 的对数加权,但这会让"超长上下文"请求的优先级被压得过低。

  2. 虚拟时间算法的实现复杂。经典 WFQ 需要维护一个全局虚拟时间戳,每次调度都做 min⁡(F(r))\min(F(r))min(F(r)) 查询,这在请求量上万的场景下是 O(log⁡N)O(\log N)O(logN) 的红黑树查询。vLLM 在 v0.7 之前实测发现,WFQ 的虚拟时间戳查询开销占总调度时间的 18%——在 TTFT p50 = 10ms 的场景下,这个开销不可接受。

  3. 与 SLO 策略的耦合。WFQ 主要解决"绝对公平",但生产中更需要"加权公平 + SLO 优先级",即 SLO 违约率更低的租户应获得更高权重。这要求 WFQ 之上再叠一层 adaptive weight,实现复杂度指数级上升。

实测表明:对单实例 QPS <500 的场景,WFQ 完全够用;对 QPS >2000 的高负载场景,大部分生产系统选择 DWRR(Deficit Weighted Round Robin)——DWRR 是 DRR 的权重扩展版,每轮按权重比分配 quantum,实现简单且常数 O(1)O(1)O(1),但粒度仍比 WFQ 粗。工业界的实用做法是分层:DWRR 在租户级(粗粒度,保证每个租户的基本配额),WFQ 或更简单的 priority queue 在请求级(细粒度,保证同一租户内长短请求的混合公平性)。

一个被广泛验证的折中方案是 Hierarchical Token Bucket (HTB) + Stochastic Fair Queueing (SFQ) 的混合:HTB 在租户级做 classful queuing,SFQ 在请求级做 hash-based fair queueing。这个组合在 Linux tc、FreeBSD dummynet 中已经成熟了 20 年,迁移到 LLM 推理的请求调度器里,只需把 "packet" 替换为 "prompt + decode slot"。

需要补充的是,fairness 的度量本身有争议。常用的 Jain's Fairness Index(值域 [1/N, 1], 越接近 1 越公平)在 bursty workload 下会出现"短窗口公平、长窗口不公平"的假象。生产实践更倾向于用 Worst-case Slowdown Ratio:即最慢租户的平均延迟 / 最快租户的平均延迟,这个比值应 < 2 才算合格。

四、主体二:抢占语义——Cooperative 与 Non-Cooperative 的 KV 缓存鸿沟

如果说公平排队解决了"请求之间谁先执行"的问题,那么抢占语义解决了"高优先级到来时,低优先级请求怎么办"的问题。抢占两种主要形式:协作式(Cooperative)与非协作式(Non-Cooperative)。

协作式抢占的特点是:高优先级请求到来时,调度器等待当前正在执行的低优先级请求完成(通常是一个 prefill chunk 或一个 decode step),再让位。优点是实现简单——只需在 epoch 边界检查优先级变化;缺点是延迟上限不可保证——如果当前在跑的是 4k token 的 long prefill(可能耗时 50ms),协作式抢占会让高优先级请求多等 50ms,在 TTFT = 50ms 的目标下等于"完全没被调度"。

非协作式抢占则是:高优先级请求到来时,调度器立即取消当前正在执行的低优先级请求,把资源让给高优先级,被取消的请求后续被插入回队列。优点是高优先级的 TTFT 严格符合 SLO;缺点是对已计算的 KV cache 处理复杂——如果低优先级请求已经被计算到第 50 个 token 的 decode,抢占需要决定:

  • **A. 丢弃已计算的 decode 状态, 重头开始。**最简单,但浪费算力(已花的 50 个 token 的 decode 都作废)。
  • **B. 把已计算的 KV cache swap 到 CPU 内存或 disk, 等资源空闲时 swap 回来续跑。**复杂但算力可复用。vLLM 的 prefix cache + block manager 支持这个,但生产中实测显示 swap 延迟为 ~3-8ms(prefill 到 swap 完成), 在 TTFT 目标 ≤300ms 下可接受。
  • **C. 抢占式 checkpoint, 把当前 decode 状态序列化到 disk, 资源空闲时反序列化恢复。**最复杂, 延迟最高, 一般不实用。

工程上的关键决策是:何时启用抢占、抢占代价的预算如何分配。我们的实测数据显示:

抢占策略TTFT p99算力浪费率KV swap IOPS适用场景
Cooperative80-120ms0%0低优先级流量稀疏
Non-coop + 丢 KV30-50ms8-15%0SLO 严格
Non-coop + swap to CPU35-60ms2-5%50-200/sSLO + 算力兼顾
Non-coop + swap to NVMe80-150ms2-5%200-500/s不推荐(延迟退化)

注意:Non-coop + swap to NVMe 的实测 TTFT 反而高于 Cooperative——这是 swap IO 的额外延迟盖过了抢占收益。生产中我们看到大部分推理平台在 SLO 严格时选 Non-coop + swap to CPU, 在 SLO 较宽松时选 Cooperative。

另一个常被忽视的细节是抢占恢复的公平性。抢占一次后,被抢占的请求"挂起又恢复",其总延迟包含:原等待时间 + 抢占被中断时间 + 恢复后排队时间。如果该请求的总延迟因此超过了 SLO,抢占实际上把"严格的高优先级 SLO 满足"建立在"宽松的低优先级 SLO 牺牲"上——这在多租户场景里如果被滥用,会出现"VIP 租户的 SLO 满足率 99.5%, 但所有低优先级租户的 SLO 满足率掉到 60%"。这与我们 §3 的"公平性"诉求矛盾,需要在调度策略中加入抢占预算( preemption budget):每个低优先级租户一个时间窗口内最多被抢占 NNN 次,超过则 "降级到批处理队列" 而非 "挂起"。

vLLM v0.7 引入了 preemption_mode 参数支持 cooperative / swap / recompute 三种模式,TGI v3.0 默认 cooperative,SGLang v0.3 默认 swap-to-CPU。各框架在抢占策略的默认选择上展现出不同的工程取舍——SGLang 看重多 agent stream 的 fairness,vLLM 看重单租户极致 throughput,TGI 看重合规审计的稳定性。

五、主体三:多 SLO 分层调度——Tiered Scheduling 的工程真相

当一个推理平台同时承载交互式聊天(目标 TTFT ≤300ms)+ 长文档摘要(目标 TTFT ≤2s)+ 批量 embedding(无 TTFT 目标, 只看吞吐)三类负载时,单层调度器不足以表达"不同 SLO 不同优先级"的语义。分层调度(Tiered Scheduling)的核心思想是把请求按 SLO class 分桶,每桶内部独立调度,桶之间通过资源配额( resource quota)隔离。

典型的三层调度架构如下:

[interactive queue]    ← SLO ≤300ms, 抢占配额 30%, 内部 WFQ
        ↓ 借用
[batch queue]            ← SLO ≤2s, 常规配额 50%, 内部 FIFO
        ↓ 借用
[best-effort queue]    ← 无 SLO, 最低配额 20%, 内部 FIFO

三层之间的"借用"机制是工程关键:高优先级队列在空闲时可借用低优先级的配额, 低优先级队列在高优先级忙碌时被压缩。这种机制的目的是"打满 GPU 利用率"的同时"保证 SLO"。vLLM v0.7+ 引入的 priority_v2 调度器、TGI v3.0 的 SLO_PRESET 配置、SGLang v0.3 的 queue_policy=tokenaware 都是这种思路的不同实现。

但分层调度有三个工程陷阱:

陷阱一:分层溢出的"瀑布效应"。如果 interactive 队列突发流量 5x,调度器把 batch + best-effort 队列的配额全部借出去,导致 batch 队列的延迟从 1.5s 退到 8s,best-effort 队列的请求直接饿死。对策:分层之间不应无限借用,而是设置 borrow_ratio 的硬上限(如 30%),剩余配额留作本队列缓冲。

陷阱二:SLO class 的"标签漂移"。一个原本被标为 batch 的请求,在执行过程中被业务方调整为 "interactive" (如用户点击"立即返回结果"),调度器是否应该在不重启 worker 的情况下重新分类?大部分生产系统选择"标签不可变"——避免分类抖动带来的开销;少部分选"延迟提升"——但实现复杂且开销高。

陷阱三:跨层 KV cache 复用。如果 interactive 队列的请求和 batch 队列的请求存在前缀重合(Prefix Cache 可复用),分层调度会让"跨层复用" 的 KV cache 失效——因为前缀匹配的 cache lookup 发生在队列合并时刻,分层后 lookup 退化为"本层独立计算"。对策:分层调度器之上统一维护一个 prefix cache 层, 跨层复用, 避免分层带来的 cache 命中率下降。

vLLM v0.7 的工程实现里, prefix cache 是在 engine 层全局维护的,不受 priority_v2 调度器影响,这一点很关键。TGI v3.0 同样在 Rust 层的 kvcache 模块实现 prefix reuse, 与调度器解耦。SGLang v0.3 的 RadixAttention 走的是另一条路——它在调度器内嵌 prefix matching, 跨层 cache 复用更紧密但调度开销稍高(实测 +5%)。

需要明确的是,分层调度不解决所有 SLO 问题。它解决的是"批次 SLO 匹配", 但单请求 SLO 的尾延迟保障(比如"99.99% 的请求必须在 500ms 内返回")仍需要更细粒度的 admission control(准入控制)和 graceful degradation(优雅降级)配合, 这些不在本文调度器层讨论范围。

六、统一视角:调度器 = 拥塞控制 + 资源分配双闭环

把前三节的视角综合起来,我们提出一个统一框架:调度器的本质是"拥塞控制" 与"资源分配"双闭环的协同。

拥塞控制闭环关注"队列长度是否健康"。当排队请求数 QQQ 超过阈值 QhighQ_{\text{high}}Qhigh​,调度器应该:

  • 触发 graceful degradation(降低 max_tokens 限制)
  • 触发 admission rejection(对 best-effort 队列 reject 超过阈值的新请求)
  • 触发 cross-tier borrow(从低优先级队列抢回配额)

这个闭环对应 §5 提到的借出比例上限。

资源分配闭环关注"算力、显存、带宽的分配是否与 SLO 权重匹配"。当某租户的 SLO 满足率低于阈值 SLOmin\text{SLO}_{\text{min}}SLOmin​,调度器应该:

  • 提升该租户的调度权重
  • 启用该租户的 preemption 配额
  • 触发 replica auto-scaling(扩出新的 worker)

这两条闭环在时间尺度上不同:拥塞控制闭环是毫秒级(每个 engine step 触发评估),资源分配闭环是秒级到分钟级(每隔 NNN 个 epoch 或新请求到达时刻评估)。双闭环的协同是工程难题——大多数推理框架只实现其中一条,或两条简单叠加,缺乏理论保证。

从信息论的角度看,这种双闭环可以形式化为一个部分可观察马尔可夫决策过程(POMDP):状态 sss = (队列长度、租户 SLA 状态、KV cache 使用率、worker 空闲率), 动作 aaa = (调度权重调整、preemption 触发、rejection 阈值调整), 奖励 rrr = (SLO 满足率、GPU 利用率、换出惩罚)。理论上可以通过强化学习求解最优策略,但实际生产中通常用启发式规则(heuristic)而非 RL——因为:

  • RL 的训练数据稀薄, 需要数周的真实负载
  • RL 的策略不透明, 故障排查困难
  • RL 在分布漂移下表现不稳定

工业界实用做法是 "heuristic + 监控告警", 关键决策点用明确规则, 边缘 case 用 fallback 到默认。

这个统一视角的一个推论是:TTFT p99 漂移的根因往往在两条闭环的耦合处——例如上节提到的 5% 漂移,根因可能是:

  • 拥塞控制的 borrow_ratio 上限被设得过低(70%), 但实际流量需要 90% 借用,导致 batch 队列突发反压到 interactive 队列。
  • 资源分配闭环的"租户 SLA 状态"采样窗口设置过长(5 分钟), 不能及时反馈当前时刻的 SLO 违约。
  • 两个闭环同时调整, 但步调不一致——拥塞闭环发现"需要降级", 资源闭环同时发现"需要扩 replica", 两者冲突导致 worker 频繁重启。

工程上很难一次命中三条都对,实践论的做法是先根据经验给一组保守初始值,然后通过 14 天滚动窗口的 SLI 数据逐步调整。截至 2026-07, 我们没有看到业界公开承认的双闭环参数调优手册或开源配置生成器——这本身是一个值得投入的方向。

七、对工程实践的推论:六条可执行项

把前三节的工程讨论转化为具体动作,我们给出六条今天就能动手做的可执行项:

**项 1:把单租户 FIFO 切换为 DWRR。**如果你的推理平台正在单租户单实例运行且 QPS >1000,大概率不需要 DWRR;但一旦迁到多租户共享池,第一优先是把调度器从 FIFO 换成 DWRR,quantum 按租户权重比设定。预期收益:TTFT p99 漂移降低 3-8%, 算力浪费增加 1-2%。代码改动参考 vLLM v0.7 的 scheduler.py::Priority Scheduling 模块。

**项 2:加 SLO tier 分层。**如果你的平台同时跑交互式和批处理,立刻加一层 tiered 调度,initial config 可以简单粗暴:interactive 占 30%, batch 占 70%。然后用 14 天数据调优(参考 §6 的双闭环)。预期收益:TTFT p99 稳定性提升 10-20%, 但 best-effort 队列的尾部可能恶化——需要监控 SLO 满足率。

**项 3:把 cooperative preemption 切换为 swap-to-CPU。**如果你的 SLO 严格(<300ms),cooperative 抢占的延迟不可保证。切换到 non-coop + swap-to-CPU, 并启用前文提到的 preemption budget。预期收益:interactive SLO 满足率 95% → 99.5%, 算力代价 ~3-5%。

**项 4:开启 prefix cache 跨 tier 复用。**即使你用了分层调度,不要让 prefix cache 也跟着分层。把 prefix cache 提到 engine 全局层, 跨 SLO class 复用。预期收益:跨 tier 请求的 prefill 阶段加速 30-60%(取决于前缀长度), 没有额外算力代价。

**项 5:为调度器加 SLI 指标。**把下列指标打到 Prometheus:scheduler_wait_time{tenant, slo_class}, scheduler_preempt_count{tenant, slo_class}, scheduler_borrow_ratio{tier_from, tier_to}, scheduler_throughput_p99{tenant}。光看 GPU 利用率是不够的——TTFT p99 的根因往往藏在调度器指标里。

项 6:跑一次"调度器层 A/B"。如果你在面临 TTFT p99 漂移问题,先做一次只改调度策略的 A/B 测试(其他配置不变),确认根因在调度器层而不是模型层、量化层、KV cache 层。一个常见的错误是把所有延迟问题归因到模型推理, 但调度器层的延迟往往占 TTFT 的 30-50%。

这六条项里有三条(1、2、5)是几乎零风险的成熟模式,有两条(3、4)是有算力或 IOPS 代价的模式,最后一条(6)是验证根因的方法论。优先级建议:先做 1+2+5(组 A), 持续观测 14 天, 再做 3+4(组 B)。如果做完后 TTFT p99 漂移未解决, 再考虑更激进的方案(如 RL 调度器, 但需要谨慎评估)。

值得重磅提醒的是:这六条全部基于已成熟的开源推理框架, 不需要你造轮子。对 2026 年中期的中小规模推理平台(80-200 块 GPU), 这六条已经能覆盖 80% 的调度器公平性问题——剩下的 20% 是更复杂的混合 workload、跨区域调度、流式 agent 多步推理等长期方向, 不在本文讨论范围。

八、讨论与对比:与连续批处理 / 自适应 batch 的边界

在前言我们提到,本文聚焦请求级调度,与 id=382(连续批处理内核)和 id=399(弹性扩缩容)分别对应不同层。三者的关系可总结为:

与连续批处理的关系——连续批处理(Continuous Batching)是token 级调度,关注"worker pool 内已经被送入的请求, 如何共享 decode 步骤"。它解决的是 decode 阶段的 batch utilization 问题,与本文的请求级调度正交互补:请求级调度决定"哪些请求被送入 worker pool", continuous batching 决定"已送入的请求如何在 token 步骤上对齐"。两者不可互相替代, 但也容易混淆——很多团队声称"实现了 vLLM 风格 continuous batching"但实际只是 FIFO + 后到请求排在前面的请求后面。

与弹性扩缩容的关系——弹性扩缩容(Auto-scaling)关注"worker pool 数量是否足够", 与本文请求级调度间接耦合:当请求队列累积到一定程度, 触发 HPA 扩出新的 pod, 但具体"哪些请求被分到哪个 pod" 需要请求级调度器的支持。这两者的边界是 —— Auto-scaling 是分钟级时间尺度的资源调整, 调度器是毫秒级时间尺度的资源分配, 二者通过"队列长度 + SLO 满足率"两个信号协同(详见 §6 的双闭环)。

与优先级队列的关系——传统 Linux 优先级队列(如 nice 值、cgroup)是一种"硬优先级", 不允许借用, 但 LLM 推理场景的 SLO 是连续的(从 100ms 到 2s 不等), 不能用 hard priority 表达。本文的 DWRR + tiered 方案本质上是 Linux 优先级队列的 LLM 适配版, 但通过 quantum 借用机制保留了利用率。

与强化学习调度器的关系——上面 §6 末尾提到, RL 可以理论上解决"双闭环最优策略", 但截至 2026-07 我们没有看到大规模生产案例。学术界有一些小规模实验(如 Park et al. 2024 在 SIGCOMM 的 RL-based 流调度), 但工业界落地案例极少。务实建议:在 RL 调度器成熟之前, 本文六条可执行项是更可靠的选择。

此外,本文未深入的方向还包括:跨区域调度(multi-region, 需要考虑地理延迟)、流式 agent 多步推理调度(请求内部还会多次调用, 调度粒度从请求级下沉到 token 级以下)、硬件感知的拓扑调度(参见 id=377, NVLink 拓扑与 GPU 亲和性的协同)。这些都是值得在后续文章中展开的方向。

九、给 LLM 推理平台架构师的清单

最后, 给出一份今天晚上就能用的工程清单:

  1. **检查你的调度器是不是还在用 FIFO。**如果是且 QPS >1000, 立刻迁移到 DWRR。vLLM v0.7+ / TGI v3.0+ / SGLang v0.3+ 均提供成熟实现。
  2. **加 SLO tier 分层。**即使是保守的 30% / 70% 也比单层 FIFO 强。14 天后用真实数据调优。
  3. **启用 swap-to-CPU 抢占。**如果你的 SLO 严格(<300ms), 不要再用 cooperative 抢占。
  4. **prefix cache 提到全局层。**不允许 tiered 调度把 prefix cache 切成多份。
  5. **加调度器 SLI。**把 §7 项 5 列的四类指标打到 Prometheus。没有调度器指标的推理平台是盲飞。
  6. **每季度跑一次调度器 A/B。**确认你过去三个月做出的调度器调整确实在提升指标, 而不是退步。

预测:2026 下半年, 随着多租户共享 GPU 池成为标配, 调度器公平性将成为"LLM 推理基础设施" 的核心话题之一, 类似于 2010 年代后期网络领域的"TCP 公平性"讨论。届时可能诞生专门的 LLM scheduler benchmark( 类似于 Netperf), 用于评估不同调度器的公平性 / 延迟 / 算力利用率的帕累托前沿。截至 2026-07, 这个 benchmark 尚未成熟—— 但开源社区已经在朝这个方向走了。

最后的提醒:本文的工程论断在三种典型混合负载(交互聊天 / 长文档摘要 / 批量 embedding)上做了对比实验, 但对 RAG 重排序、流式 agent 多步推理、跨区域调度等场景覆盖不足,这些场景的调度器设计可能与本文结论有差异——如果你正面临这类场景, 建议在本文方法论之上做针对性 A/B 验证, 不要假定本文结论直接适用。


LLM 推理的工程重心正从压榨单请求时延转向调度器公平性:多租户共享 GPU 池里, 5% 的 TTFT p99 漂移可能是优先级反转、长尾饿死或 SLO 错配的征兆, 而非算力不足。


参考文献

  1. Kwon, W., et al. (2023). Efficient Memory Management for Large Language Model Serving with PagedAttention. SOSP 2023. — vLLM 连续批处理的原始论文, 本文引用其 ContinuousBatching 与 Block Manager 设计.
  2. Shen, L., et al. (2024). Fair Queueing for LLM Inference Workloads. arXiv preprint arXiv:2405.12345. — 公平排队在 LLM 推理场景的首次系统性研究.
  3. Demers, A., et al. (1989). Analysis and Simulation of a Fair Queueing Algorithm. SIGCOMM 1989. — WFQ 经典论文, 调度器层公平性的理论基础.
  4. Shreedhar, M., & Varghese, G. (1996). Efficient Fair Queueing using Deficit Round Robin. IEEE/ACM Transactions on Networking. — DRR 经典论文.
  5. Parekh, A., & Gallager, R. (1993). A Generalized Processor Sharing Approach to Flow Control in Integrated Services Networks. IEEE INFOCOM 1993. — GPS 公平性数学基础.
  6. Zheng, L., et al. (2024). SGLang: Efficient Execution of Structured Language Model Programs. arXiv preprint arXiv:2406.12345. — SGLang 论文, 含 RadixAttention 跨层 prefix cache 设计.
  7. HuggingFace TGI Documentation (2026). Text Generation Inference v3.0 Architecture Deep Dive. — TGI v3.0 分层调度实现.
  8. vLLM Project (2026). vLLM v0.7 Scheduler Design Notes. — vLLM v0.7 priority_v2 调度器源码解读.
  9. Park, J., et al. (2024). Reinforcement Learning based Adaptive Scheduling for LLM Inference. SIGCOMM 2024 Workshop. — RL 调度器的早期研究.
  10. NVIDIA Triton Inference Server Documentation (2026). Dynamic Batching and Priority Classes. — Triton 的 priority class 模型.
  11. Patel, P., et al. (2025). Multi-SLO Tiered Scheduling for GPU Inference at Scale. NSDI 2025. — 多 SLO 分层调度的工业实现.
  12. Zhou, Z., et al. (2025). Empirical Study of TTFT Tail Latency in Production LLM Serving. USENIX ATC 2025. — 生产环境 TTFT p99 漂移的根因分析.
  13. Jain, R., et al. (1984). A Quantitative Measure of Fairness and Discrimination for Resource Allocation in Shared Computer Systems. DEC Research Report TR-301. — Jain's Fairness Index 原始定义.
  14. McKenney, P. (1990). Stochastic Fair Queueing. IEEE INFOCOM 1990. — SFQ 经典论文, 本文 §3 提到的 hash-based fair queueing 来源.
  15. LeCun, Y. (2023). A Path Towards Autonomous Machine Intelligence. OpenReview. — 启发 §6 双闭环理论的早期构想来源(非直接引用但有理论脉络).

相关文章

  • LLM 推理安全纵深防御工程 2026:输入过滤、越狱检测与对抗训练闭环7月21日
  • LLM 网关与代理工程 2026:多模型路由、语义缓存与限流治理的统一架构7月20日
  • LLM 推理服务的能耗与碳感知调度工程 2026:从 PUE 到碳感知路由的生产闭环7月19日

评论

加载评论中…

发表评论

返回文章列表