WALL · 一本排队与拥塞的小书
撞墙
你的服务器还有 20% 的富余,用户已经在骂了。你的第一反应大概是加机器、优化代码、换更快的数据库——这三件事都在打同一个靶子:速度。而这本书想说的是,你打错靶了。
慢不是速度问题,是余量问题。等待时间 = 满的程度 × 不齐的程度 × 一次要多久,三个因子里只有一个是速度,而且是唯一线性的那个。
这本书的招牌
五个系统,吞吐完全相同、平均服务时间完全相同、因此利用率完全相同(都是 80%)。按任何一个标准监控指标看,它们是同一个系统。唯一的区别是「整齐程度」:
走法 到达 服务 平均等待 天花板(我最多能忍 2 个服务时长) ───────────────────────────────────────────────────────────── D/D/1 ca²=0 cs²=0 0.0000 100.0% ← 一个人都没等过 D/M/1 ca²=0 cs²=1 1.6927 80.0% M/D/1 ca²=1 cs²=0 2.0000 80.0% M/M/1 ca²=1 cs²=1 4.0000 66.7% ← 教科书默认款 M/H₂/1 ca²=1 cs²=10 22.0000 26.7% ← 你的系统大概在这儿
机器没换、活没多、速度没变,平均等待从 0 走到 22 个服务时长。最后一列更狠:同样的容忍度,第一行能把机器跑到 100%,最后一行只能跑到 26.7%——七成多的产能必须空着。
而这个区间,在你的监控面板上是完全不可见的。
不是模拟:我在这台电脑上真的排了一遍队
排队论没有标准库可以对照(不像压缩之于 zlib)。所以这本书的对照对象是机器本身:真的 CPU busy loop 当服务、真的时刻表当到达、真的单线程服务台,烧掉 27 秒排出 10200 位顾客。
队 n 真机量到 Lindley 预测 纸上公式 ───────────────────────────────────────────────────────────── D/D/1 ρ=0.8 800 0.001ms 0.000ms 0.000ms M/D/1 ρ=0.8 1400 4.263ms 4.256ms 4.000ms M/M/1 ρ=0.8 3000 6.686ms 6.680ms 8.000ms M/M/1 ρ=0.5 1000 1.753ms 1.751ms 2.000ms M/M/1 ρ=0.7 1400 3.845ms 3.843ms 4.667ms M/M/1 ρ=0.9 2600 18.524ms 18.507ms 18.000ms ★ 把真机**真的烧掉**的服务时长喂回 Lindley 递推,逐个顾客比对开始时刻: 10200 位顾客,中位误差是**个位数微秒**。
第一行是最想让你看见的一行:同一台机器、同样忙到 80%、同样的吞吐,只要来得准走得准,800 个请求里没有一个等过哪怕一毫秒。
卷 I
排起来
QUEUE队不是从「机器不够快」来的。它有两个成因,而速度只是其中半个。
卷 II
不齐
JITTER第二个成因。它没有名字,所以你一直没在账单上看见它。
卷 III
那面墙
WALL一条你没见过的曲线,和它在 100% 处的那道竖线。
卷 IV
加人
SCALE加机器有用,但用处和你以为的完全不是一回事。
卷 V
插队
ORDER总时间是定死的。调度只决定这笔账由谁付。
卷 VI
留余
SLACK你买的从来不是速度,是余量。
写给谁
- 看过 p99 曲线,但说不清它为什么长那样的人;
- 被问过「服务器利用率才 40%,是不是太浪费了」而答不上来的人;
- 做过容量规划,但心里知道那个「乘以 1.5」的系数是拍脑袋来的人;
- 以及每一个排过队、堵过车、觉得「隔壁那条队总是更快」的人。
不打算做的事
- 不教你怎么优化代码。这本书从头到尾在说,那是三个因子里效果最小的一个。
- 不推荐任何具体的技术选型。这里的东西对所有语言、所有框架一样成立。
- 不假装公式很准。每一个近似都会标出它在哪里失灵、偏多少(第 8 章有一整张表)。
怎么读这本书
- 按顺序读。后面每一章都在用前面的结论,尤其是第 2、8、9 章那三个地基。
- 每章开头那个「▷ 先估一个数」,真的先估一个。整本书都在治「线性直觉在非线性世界里偏得多离谱」这个毛病,而唯一有效的疗法是让你亲眼看见自己偏了几倍。
- 时间紧的话,最短路径是:第 1 章(那张对照表)→ 第 8 章(三个因子)→ 第 9 章(那面墙)→ 第 12 章(招牌)→ 第 24 章(自查表)。五章,一小时,够你回去改三个配置。
- 所有 demo 都可以拖。数字全是引擎当场算的,不是写死的图片。