7.4 Goodput 与 SLO 感知调度:以有效吞吐为优化目标
Raw QPS 与 Goodput 的区别、SLO 的构成(TTFT/TPOT/端到端)、分位点约束的意义、SLO 感知调度的机制、Goodput 的测量方法
7.1 说过”SLO 盯分位点不盯均值”,7.2 说 DistServe 把优化目标改成 Goodput——这一节把这两个概念系统讲透。Raw QPS(每秒请求数)不等于用户体验:一个 90% 请求都超时的服务,QPS 再高也是废的。Goodput 就是”满足 SLO 的吞吐”,它把服务质量从”旁挂指标”变成”优化目标本身”。这一节也讲 SLO 感知调度怎么在运行时实现它。
📑 目录
- 1. 从 QPS 到 Goodput:指标革命
- 2. SLO 的解剖:用什么指标、卡什么阈值
- 3. 为什么分位点(P95/P99)而不是均值
- 4. Goodput 的测量:同一条曲线两种读数
- 5. SLO 感知调度:运行时怎么保 Goodput
- 6. 解耦与 SLO 的天然契合
- 7. 工程落地:SLO 监控与告警设计
- 📝 总结
- 🎯 自我检验清单
- 📚 参考资料
1. 从 QPS 到 Goodput:指标革命
1.1 传统指标的问题
| 指标 | 定义 | 盲区 |
|---|---|---|
| QPS / RPS | 每秒处理的请求数 | 慢请求也算”处理”——超时请求同样计入 |
| 吞吐(Tokens/s) | 每秒生成 token 数 | 不区分有效/无效输出 |
| 平均延迟 | 请求延迟的算术平均 | 尾部被均值掩盖(7.1 的干扰正是打尾部) |
1.2 Goodput 的定义
或等价地:
📌 关键点:Goodput 是”达标的吞吐”——一个请求要么在 SLO 内完成(计入),要么超时(不计入)。它不是新指标,而是把服务质量乘进吞吐里。DistServe 把 goodput 作为系统优化目标,意味着调度器的每个决策都在为”SLO 内完成率”服务,而不是为”token 总数”服务。
1.3 为什么必须换指标
一个反直觉的事实:高吞吐与高 Goodput 在资源受限时互相矛盾。把并发拉满,吞吐确实涨,但每个请求都变慢、SLO 达标率暴跌——Raw QPS 上升而 Goodput 下降。服务型系统优化的是后者:
同一台机器、两种配置:
配置 A:并发 512 → 吞吐 5000 tok/s,SLO 达标率 99% → Goodput ≈ 4950
配置 B:并发 2048 → 吞吐 9000 tok/s,SLO 达标率 50% → Goodput ≈ 4500
配置 B 的”吞吐更高”,但用户感受到的是”一半请求太慢”。用 Goodput 选型,配置 A 才是赢家。
2. SLO 的解剖:用什么指标、卡什么阈值
2.1 LLM 服务的 SLO 指标集
| SLO 指标 | 覆盖阶段 | 典型阈值(生产常见) |
|---|---|---|
| TTFT(首 token 时间) | Prefill + 排队 | P95 < 1-3s(聊天场景) |
| TPOT / ITL(每 token 时间) | Decode | P95 < 50-100ms |
| 端到端延迟 | 全程 | P95 < 10-30s(长输出按预期时长缩放) |
| 错误率 | 全程 | < 0.1-1% |
2.2 SLO 的三个要素
一个完整的 SLO 语句包含三要素:
[指标] 的 [分位点] 要 [阈值] 以内
│ │ │
TTFT P95 < 2s
- 指标:TTFT / TPOT / 端到端 / 错误率
- 分位点:P50 / P90 / P95 / P99(决定”允许多少请求慢”)
- 阈值:具体毫秒/秒数(与业务场景强相关)
💡 提示:别把”延迟平均值 < 2s”当 SLO——那是伪 SLO。没有分位点的 SLO 无法约束尾部,而 7.1 已经证明 LLM 服务的尾部恰恰最脆弱。写 SLO 时强制自己写全三要素。
2.3 多阶段 SLO 的叠加
生产服务通常同时有 TTFT 和 TPOT 两个 SLO(甚至端到端)。两个都要满足:
这也正是解耦的动机之一(7.1 的资源耦合):混合架构下同时守两个 SLO 很难,解耦后各守各的(7.6)。
3. 为什么分位点(P95/P99)而不是均值
3.1 均值掩盖尾部
一个典型的延迟分布(LLM 混合负载):95% 的请求 100ms 完成,5% 的请求 5s。均值 345ms 看着还行,但 P99 = 5s 已经不可用。均值是分布的单点摘要,对长尾无能为力。
3.2 尾部的业务含义
- 用户对”慢”的感知是非线性的——最后一个慢请求毁掉整个交互体验
- 下游系统(调用方)超时按分位点设计——你的 P99 超时,下游的重试风暴就来了
- 分布式系统里尾部延迟会级联放大(tail at scale 现象)——单个服务的 P99 问题会传导到整条调用链
3.3 分位点的统计含义
- P95:95% 的请求达标,5% 允许超时(约每 20 个请求允许 1 个慢)
- P99:99% 达标(约每 100 个请求允许 1 个慢)
分位点越高,调度的”安全余量”要求越大——P99 SLO 比 P95 贵(需要更多资源余量),写 SLO 时按业务真实需求选,别盲目上 P99。
📌 关键点:分位点与资源的关系:达标分位点每上一个台阶,所需资源余量非线性增长(P99 的资源成本通常明显高于 P95)。生产实践:对外 SLO 写 P95,内部优化看 P99——既保体验又控成本。
4. Goodput 的测量:同一条曲线两种读数
Goodput 可以用负载-延迟曲线理解:
延迟(P95 TTFT)
│ ┌────────── 超 SLO 区(不达标)
│ ╱────┘
│ ╱───┘ ← SLO 线(如 2s)
│ ╱──┘
│╱─┘ ← 达标区
└───────────────────────→ 请求速率
↑ ↑
Raw 吞吐上限 Goodput 上限
(延迟爆炸点) (与 SLO 线的交点)
- Raw 吞吐上限:系统”崩溃前”能扛的最大速率(延迟无约束)
- Goodput 上限:延迟恰好压在 SLO 线下的最大速率
- 两者之间的区域:看似能扛、实则不达标的”虚胖区”
💡 提示:压测时别只看”打爆了没”——在 SLO 线下找最大速率才是 Goodput 压测。流程:固定负载 → 逐步加压 → 记录 P95 延迟与 SLO 线的交点 → 该点的 QPS 就是 Goodput 上限。7.6 实战会完整走一遍。
5. SLO 感知调度:运行时怎么保 Goodput
指标定了,调度器怎么执行?SLO 感知调度(SLO-aware scheduling)的常用机制:
5.1 准入控制(Admission Control)
拒绝/降级会拖垮 SLO 的请求——队列已深时新请求要么排队等(TTFT 爆)要么直接拒绝(错误率涨)。调度器维护”当前资源状态 + SLO 余量”的估计,超限时:
- 拒绝新请求(返回 429/排队提示)
- 或降级(用更小的 max_tokens、更低的优先级)
5.2 优先级调度(Priority Scheduling)
请求按 SLO 紧急性排序:快超时的请求插队(如 EDF——最早截止时间优先),避免”眼看要超时还在排队”。
5.3 请求级资源预留
调度器预估每个请求的资源需求(prompt 长度 → prefill 时长;输出长度 → KV 占用),预留而不是事后补救——vLLM 的 scheduler 本身就有按 token 数做预算的逻辑(第 3 章),SLO 感知调度在此基础上加”时间”维度。
5.4 过载保护(Overload Protection)
持续过载时:降并发 → 降 max-num-seqs → 拒绝 + 熔断。宁可拒一批请求,不拖垮全部请求——这是 goodput 思想在故障场景的延伸。
📌 关键点:SLO 感知调度的哲学——调度器做的是”预算管理”而非”尽力而为”。尽力而为在低负载时没问题,但一过载就全面崩盘;预算管理在过载时”牺牲少数保多数”,Goodput 反而更稳。
6. 解耦与 SLO 的天然契合
回到第 7 章主线——解耦为什么天然利好 Goodput:
| 混合架构 | 解耦架构 |
|---|---|
| TTFT 和 TPOT 共用一个资源池 | 两个池各守一个 SLO |
| Prefill 突发直接冲击 Decode 尾部 | 突发被 prefill 池隔离,Decode 尾部稳定 |
| 一个旋钮调两个目标 | 每个池独立调参(TP、并发、batch) |
| 资源按”峰值耦合需求”配置 | 资源按各自 SLO 需求独立配置 |
- vLLM 官方文档把”控制 tail ITL”列为 disaggregated prefill 的核心动机
- DistServe 的 goodput 提升(7.4×)正是”解耦 + SLO 感知”组合的结果
💡 提示:理解这条因果链——解耦让”独立 SLO”成为可能,Goodput 让”独立 SLO”成为目标。没有 Goodput 视角,解耦只是”把进程拆开”;没有解耦,Goodput 优化在混合架构里处处受制。两者互为对方存在的理由。
7. 工程落地:SLO 监控与告警设计
7.1 该采什么指标
- 分位点直方图:TTFT/TPOT/端到端的 P50/P90/P95/P99(别只存均值!)
- 达标率:SLO 达标请求比例(Goodput 的分子)
- 过载信号:队列深度、拒绝率、GPU 利用率
7.2 告警设计
- 告警条件写在 SLO 达标率上(如”P95 TTFT > 2s 持续 5 分钟”),而不是均值
- 分级:P90 超标(警告)/ P95 超标(严重)/ P99 超标(紧急)
- SLO 预算(error budget):允许的累计不达标时间(如每月 1%),用于”发布/扩容”决策
7.3 压测与容量规划
- 压测目标 = 找 Goodput 上限(第 4 节的方法)
- 扩容触发 = Goodput 接近上限 + 趋势向上
- 容量报告 = “当前峰值负载下,Goodput 余量 x%“——用 SLO 语言汇报,管理层才听得懂
📌 关键点:工程上最容易被忽视的一环——把 Goodput 写进容量规划和发布流程。团队常见的死法:上线看 QPS 涨了 20% 欢呼,实际上 P99 已经悄悄超了 SLO 一个月。指标选错了,优化方向全错。
📝 总结
- Goodput = 吞吐 × SLO 达标率:把服务质量乘进吞吐,才是服务的真实产出
- SLO 三要素:指标(TTFT/TPOT/端到端)× 分位点(P95/P99)× 阈值——缺一不可
- 分位点而非均值:均值掩盖尾部,P99 成本远高于 P95,按需选择
- SLO 感知调度:准入控制、优先级(EDF)、资源预留、过载保护——预算管理而非尽力而为
- 解耦 ↔ Goodput 互相成就:独立 SLO 是解耦的动机也是解耦的红利
- 工程落地:分位点直方图、达标率告警、error budget、Goodput 容量报告
🎯 自我检验清单
- 用自己的话定义 Goodput?为什么”高吞吐低达标率”是虚胖?
- 写出一个完整的 SLO 语句(三要素齐全),并指出”均值 SLO”错在哪
- P95 与 P99 的资源成本差异?什么场景选哪个?
- 如何压测出系统的 Goodput 上限?(画负载-延迟曲线说明)
- SLO 感知调度的四种机制?“预算管理 vs 尽力而为”的区别?
- 解耦为什么让”独立 SLO”成为可能?因果链是什么?
- 监控里为什么必须存分位点直方图而不是均值?
📚 参考资料
- Zhong et al., DistServe(Goodput 定义与优化)(https://www.usenix.org/conference/osdi24/presentation/zhong-yinmin)
- Google SRE 手册:Service Level Objectives 章节(https://sre.google/sre-book/service-level-objectives/)
- vLLM 官方文档:Per-request Metrics(SLO 相关指标)(https://docs.vllm.ai/en/latest/features/per_request_metrics.html)
- Dean & Barroso, The Tail at Scale(CACM 2013)(https://cacm.acm.org/research/the-tail-at-scale/)