卷 VI · 留余CH 24深度 24/24

量你自己的

前二十三章都是我的数字。这一章把工具交给你:三个要量的数、一张诊断表、一台计算器,以及一件几乎所有教程都不会告诉你的事——你量出来的数和公式对不上,多半是正常的。

★ 自查表抽样噪声有多大继续往下走

▷ 先估一个数

你在生产环境上量了 3000 个请求,算出平均排队时间是 6.7 毫秒

而按公式(利用率 80%、平均服务时间 2 毫秒、纯随机),理论值应该是 8.0 毫秒

差了 16%。这说明什么?

A 模型不对,真实系统比理论好——排队论过于悲观 B 测量有问题,得去查埋点 C 什么都不说明。这个样本量下,这个偏差完全正常 D 说明利用率其实没到 80%

要量的三个数

整本书压缩成一次操作,就是去量这三个数:

要量什么怎么量健康区间
① 利用率 ρλ × E[S] ÷ 服务台数。注意用请求速率 × 处理时间算,而不是直接看 CPU(CPU 不等于你的瓶颈)看第 9 章的 ρ★,取决于 ② 和你的容忍度
② 不齐 c²方差 ÷ 均值²,从你已有的延迟直方图算,一行代码< 1 很好,1–4 正常,> 4 值得查
③ 单次时间 E[S]p50 延迟(在低负载时测,否则含排队)业务定

三个数量到了,第 8 章那个公式就能用了,而更重要的是它们指向三条完全不同的排查路线

◆ 诊断表:先做便宜的

发现系统慢的时候,按这个顺序问:

  1. ρ 是多少?如果 > 0.85——先加机器。第 10 章证明过:等待减半只需要加 1−ρ 的产能。在 90% 的地方那是 10%,这是三条路里最便宜、最快、最可预测的一条。
  2. c² 是多少?如果 > 4——去找那一小撮慢请求。第 5 章证明过:10% 的请求慢 100 倍,贡献了 99.9% 的方差。常见嫌疑人:大 key、冷缓存、N+1 查询、重试、某个大客户。
  3. 池子有多大?如果服务台数 < 4——先想办法合并池子。第 14 章:同样的利用率,小池子的队长得多。检查有没有不必要的隔离、分片、亲和性绑定。
  4. 队列有上限吗?如果无界——加上限。第 21 章:K = 产能 × 能容忍的等待。或者更好,按排队时长丢弃(CoDel 式)。
  5. 是不是扇出的?如果一个用户请求打到 > 10 个后端——单机的余量要求要按扇出深度倒推。第 16 章:扇出 100 台时,你要的是单机 p99.99。
  6. 最后才是 E[S]:优化代码、换更快的机器。这是唯一线性的因子,也通常是工程量最大的一条。

大多数团队的默认顺序是反的:先从第 6 条开始。

为什么你量出来的数和公式对不上

这一节是这本书最后一个、也是最重要的诚实交代。

第 11 章我在真机上跑了一条 M/M/1 队列,ρ=0.8,3000 个请求,量出来平均等待 6.6857 毫秒。而公式说是 8.0000 毫秒

差了 16%。当时我的第一反应是「哪里错了」。

什么都没错。是样本量的问题。

我用模拟器在完全相同的条件下(同样 n=3000,同样 ρ=0.8)跑了 400 次,看看「样本均值」这个统计量本身的分布:

# 稳态真值:8.00 毫秒
# n=3000 时,样本均值的分布:

  p5   = 6.48 ms
  p50  = 7.76 ms
  p95  = 9.79 ms

# ★ 也就是说,在这个样本量下,
#   你量出 6.5 到 9.8 之间的任何一个数都完全正常。
#   而真机那次量到的 6.6857 落在第 13 个百分位 —— 有点低,但一点也不奇怪。

为什么方差这么大?因为排队时间是高度自相关的。同一个忙期里的所有顾客共享同一段坏运气(第 4 章)。所以你的 3000 个样本里,有效独立样本只有几百个——大致是「忙期的个数」,而忙期平均包含 1/(1−ρ) 个顾客。

◆ 三条实用的推论

1. 不要用短窗口的平均延迟做告警。如果你的告警是「5 分钟平均排队时间超过 X 就报警」,而 5 分钟只有几千个请求,那么你会收到大量假警报——不是系统坏了,是统计噪声。

2. 报告改善时要给区间。「优化后平均延迟从 8ms 降到 6.7ms,改善 16%」——如果样本量是 3000,这个「改善」完全可能是噪声。ρ 越高,需要的样本量越大(有效样本数按 1−ρ 缩小)。

3. 分位数比平均值更稳。p50 的抽样方差比平均值小得多,因为它不受尾巴影响。这是又一个该报中位数而不是平均值的理由(第 4 章给的是另一个理由)。

八件可以明天就做的事

  1. 方差 ÷ 均值² 打成一条曲线,挂在利用率旁边。你的监控第一次有能力回答「为什么慢」,而不只是「有多慢」。
  2. 给所有定时任务加随机抖动。成本几行代码,收益是把 ca² 从「所有人都在整点」压回接近 1。
  3. 检查每一个无界队列。线程池、消息队列、连接等待队列。给它们设上限,或者按排队时长丢弃。
  4. 把重试策略从「重试 N 次」改成「重试预算占比」。前者在大面积故障时会把流量放大 N 倍。
  5. 找出你的 贡献大户。按耗时排序,看最慢的 1% 是什么。它们贡献了大部分排队成本。
  6. 把「大请求」隔离到独立的池子。不改任何代码逻辑,只改路由,就能把一条 大的队拆成两条小的。
  7. 压测改成固定到达率模式。「固定并发」模式测的是一个 ca² 很小的假世界。
  8. 算一下你的服务「能挂几台」k < N × (1 − ρ)。很多团队会发现答案是零。
▸ 在现实里

回到你自己的日程表。这本书最私人的一个应用。如果你总觉得「事情永远做不完,而且每件事都拖很久」,去量三个数:你手上同时有几件事在进行(L)、你每周完成几件(λ)、于是每件事平均要多久(W = L/λ)。然后试着把 L 砍一半,什么都不改变。第 2 章那条恒等式保证 W 会跟着减半。

去测你家路由器的缓冲区膨胀。开一个大下载,同时 ping 一个外网地址,看延迟涨多少。如果从 20 毫秒涨到几百毫秒,那就是第 22 章那张表。然后打开路由器的 SQM/fq_codel,再测一次。这是这本书里你今晚就能自己复现的一个结论。

✗ 这个直觉是错的
既然抽样噪声这么大,那排队论的公式在实践中就没什么用——反正测不准。 公式最有用的地方从来不是「精确预测等待时间」,而是告诉你哪个旋钮值得拧、拧多少。而这些结论对噪声非常不敏感。

举几个这本书里的结论,它们全都不依赖精确测量:

  • 「等待减半需要增加的产能等于当前余量」——这是比例关系,不需要知道等待的绝对值;
  • 「ρ 从 90% 到 95%,等待翻倍还多」——同样是比例;
  • 「一条队比四条队快 4.57 倍」——比值;
  • 「扇出 100 台,p99 会变成 63.4% 的概率」——纯概率,和你的延迟绝对值无关;
  • 「Σ ρₖ×Wq,k 是常数」——守恒律,精确成立。

需要精确测量的只有一件事:你现在站在曲线的哪一段。而那只需要知道 ρ 的量级(0.5 还是 0.9),不需要小数点后两位。

◇ 结算

C什么都不说明。在 n=3000 的样本上,稳态值 8.00 毫秒的系统,量出 [6.48, 9.79] 之间的任何数都在正常的 90% 区间内。6.7 落在第 13 个百分位。

这道题想教的方法是:看见理论和实测不符时,先问「这个差距在这个样本量下算大吗」,再去怀疑模型或者测量。而回答这个问题的办法很简单——用模拟器在相同条件下跑几百次,看看样本均值本身的分布有多宽。

A 「排队论过于悲观」——这个结论至少要看几十次独立测量的中位数才敢下。而且要小心:Kingman 公式确实系统性偏大(第 8 章那张表),但那是另一回事,与这次的 16% 无关。 B 「测量有问题」——这个怀疑在别的场合是对的(第 2 章说过 Little 定律可以当检查器用),但 16% 的偏差还远远够不上「测量出错」的门槛。 D 「利用率其实没到 80%」——有可能,而且值得顺手核对一下。但同样,16% 的等待偏差只对应 ρ 从 0.80 漂到 0.78,这个量级的漂移在 3000 个请求的样本里也是噪声。

这一章的一句话

去量三个数:有多满、有多不齐、一次多久;然后按「先做便宜的」顺序动手。

继续往下走

这本书刻意停在了几个地方,下面是那几扇门。

如果你想把数学补齐

  • Mor Harchol-Balter,《Performance Modeling and Design of Computer Systems》(2013)。这是我见过写得最好的排队论教材,而且完全面向计算机系统。第 18 章那些 SRPT 结果就出自她的研究。如果只读一本,读这本。
  • Leonard Kleinrock,《Queueing Systems》(两卷,1975–76)。经典,第 19 章那条守恒律就是他的。数学更重,适合当参考书。
  • Neil Gunther,《Guerrilla Capacity Planning》。USL 的出处,第 15 章的来源。书名里的「游击」指的是「在没人给你时间和数据的现实里怎么做容量规划」。

如果你想往控制论走(第 22 章那扇门)

这本书讲的是被动的排队。而拥塞控制、自动扩缩容、限流器,都是带反馈的系统,它们有另一套理论。

  • Philipp K. Janert,《Feedback Control for Computer Systems》。用工程师听得懂的话讲 PID 和反馈回路,例子全是软件系统。
  • Van Jacobson 1988 年那篇《Congestion Avoidance and Control》。互联网没有在 1986 年崩溃,很大程度上因为这篇论文。二十多页,值得读原文。
  • Chiu & Jain 1989 关于 AIMD 收敛性的那篇。第 22 章那张收敛图的出处。
  • 再往上是控制论本身:Ashby 的必要多样性定律说的是「控制器的多样性必须匹配被控对象的多样性」——而这本书从头到尾在讲的「不齐」,正是那个多样性。这两个学科在这里握手。

如果你想往运筹和精益走(第 23 章那扇门)

  • Donald Reinertsen,《The Principles of Product Development Flow》。把排队论直接用在产品研发流程上,我认为是这个方向最好的一本。它有一句话可以当这本书的题词:「你无法管理你没有量化的队列,而大多数组织连队列在哪都不知道。」
  • Eliyahu Goldratt,《目标》。用小说讲约束理论。它讲的「瓶颈决定一切」和这本书的「余量决定一切」是一枚硬币的两面。
  • 交通流理论:如果第 23 章那条抛物线勾起了你的兴趣,关键词是 fundamental diagram、shockwave theory、以及「三相交通流理论」(Kerner)。

这本书没讲的东西

诚实地列一下缺口,免得你以为自己学完了:

  • 排队网络:多个队列串起来(微服务链路就是)。有一套漂亮的理论(Jackson 网络、BCMP),核心结论是「在某些条件下,各个节点可以当成独立的队来算」——但那些条件在现实里经常不成立。
  • 重尾的正经处理:第 5 章和第 21 章只是提了一下 =∞。真正的重尾排队论(heavy-tailed queueing)是一个活跃的研究领域,结论和本书大不相同。
  • 相关到达:重试、推送、雪崩这类「到达之间有强相关」的情况。本书的公式在这里会低估,而这正是线上事故最常见的形态。关键词是 MAP(Markovian Arrival Process)、self-similar traffic。
  • 调度理论的正经版本:第 17–19 章只讲了最基本的几个策略。完整的调度理论(包括那些「什么问题是 NP 难的」的结果)是另一本书的量。

最后一句

这本书从「慢,不是因为不够快」开始,到这里可以给出完整版了:

慢是余量不够,而余量之所以不够,一半是因为你用得太满,一半是因为你的活太不齐。你能买到的东西里,速度是最贵的那个,也是效果最小的那个。

而那 30% 空着的机器,从来不是浪费。那是你花钱买下来的、唯一能吸收这个世界的不确定性的东西。