卷 I · 排起来CH 02深度 2/24

一条定律,三个字母

排队论里几乎所有公式都要先问「到达是什么分布」「服务是什么分布」「几个台子」。只有一条不问。它对任何系统都成立,包括你还没建模、甚至还没看懂的系统——这让它成为你手上最好用的一把螺丝刀。

Little 定律三条路一个数不需要任何假设

▷ 先估一个数

你在做一个订单系统。你知道两件事:每天进来 1200 个订单随时去看,系统里大约压着 150 个还没处理完的订单

你不知道任何别的:不知道处理逻辑、不知道有几个人在处理、不知道优先级怎么排、不知道订单大小分布。

请问:一个订单从进来到处理完,平均要多久?

A 数据不够,这题答不了 B 大约 3 小时 C 大约 8 小时 D 要看订单分布,可能几分钟也可能几天

把同一件事数两遍

设想一个系统——任何系统。人进去,待一会儿,出来。

现在我要问:这个系统里平均有多少人?

有两种数法。

第一种:按时刻数。随便挑一个时刻,进去数人头,记下来。挑一万个时刻,把数字平均。这个平均值叫 L(系统里的人数)。

第二种:按人数。不数人头,改为跟着每个人,记下他在里面待了多久。把所有人的停留时间加起来,除以观察的总时长。

关键在于:这两种数法在数同一样东西

# 假设观察了 T 这么长的时间,期间来了 N 个人

# 按时刻数:把「此刻有几个人」对时间积分,再除以 T
L = ∫ 人数(t) dt ÷ T

# 按人数:把每个人待的时长加起来,再除以 T
L = ( Σ 每个人待的时长 ) ÷ T
  = ( N × 平均停留时间 ) ÷ T
  = ( N ÷ T ) × 平均停留时间
  = λ × W                          ← λ 是到达率,W 是平均停留时间

这就是 Little 定律,1961 年由 John Little 证明:

L = λ × W

  L  系统里平均有几个人(或几个请求、几个订单、几件在制品)
  λ  平均每单位时间来几个(到达率,也等于稳态下的吞吐)
  W  每个人平均在系统里待多久

停一下,看看上面那段推导用到了什么假设。

什么都没用到。

没有假设到达是泊松的;没有假设服务时间的分布;没有假设先来后到;没有假设几个服务台;没有假设服务台之间怎么协作;甚至没有假设这是个「队列」——它可以是一间教室、一个仓库、一条流水线、一个人的待办清单。

它唯一要求的是稳态:长期来看,进去的人数和出来的人数得相等(不然人数会一直涨)。

◆ Little 定律不是排队论定理

它是一条记账恒等式。它成立的方式,和「收入 − 支出 = 利润」成立的方式一样:不是因为世界恰好如此,而是因为它就是同一件事的两种记法。

这带来一个非常实用的后果:你不需要理解一个系统,就能对它用 Little 定律。三个量里量到两个,第三个就是白送的。而在真实系统里,L 和 λ 通常很好测(队列深度、QPS 都在监控上摆着),W 却很难测(要给每个请求打点、串起来、算分位数)。

上面这台 demo 里,我用三条完全不同的代码路径算同一个 L:

  1. λ × W:量到达率,量每个人的停留时间,相乘。
  2. 时间积分:把每个人的停留区间铺在时间轴上,算总覆盖长度除以窗口长度。
  3. 随机抽样:在窗口里随机挑四万个时刻,每个时刻数一次人头,平均。

默认参数下,三条路给出 4.07704.07704.0851。第三条略有出入是因为它只抽了四万个样本——它是三条里唯一一条真正的统计估计,另外两条是精确记账。

然后你可以把四个旋钮拧到任何组合:到达完全定时也行、忽快忽慢也行,服务整齐也行、重尾也行,一个台子也行、四个也行。三条路永远对得上。

∑ 算一遍:它还有个更有用的兄弟

把「系统」的边界画在不同地方,就得到不同的版本。这是实战中最常用的技巧:

# 边界画在「整个系统」(排队 + 被服务)
L  = λ × W          L 是系统里的人,W 是从进门到出门

# 边界只画在「队列」(不含正在被服务的)
Lq = λ × Wq         Lq 是队里的人,Wq 是纯等待时间

# 边界只画在「服务台」
ρ  = λ × E[S]       ← 这就是利用率的定义!
                       「服务台里平均有几个人」= 它有多大比例时间在忙

第三行值得多看两眼:利用率本身就是一次 Little 定律的应用。把服务台看成一个只装得下一个人的小系统,那么「里面平均有几个人」在 0 到 1 之间,正好就是「它有多大比例的时间是忙的」。

它能替你做什么

1. 从两个好测的数推出难测的那个。这是最常见的用法。上面那道题就是:1200 单/天,压着 150 单,那么 W = L / λ = 150 / 1200 = 0.125 天 = 3 小时。你完全不需要知道系统内部长什么样。

2. 反过来,用它来定容量。「我们要求 p50 处理时间在 2 小时内,每天 1200 单」——那么在制品数量最多只能压 1200 × 2/24 = 100 单。这直接变成一个可以挂在看板上的WIP 上限

3. 最重要的一条:限制在制品,就是在直接缩短周期时间。把 L 砍一半,在 λ 不变的前提下,W 必然砍一半。这不是「可能会改善」,这是恒等式。精益生产和看板方法里那条「限制 WIP」的规矩,数学依据就是这一行。

✎ 术语正名:「吞吐」和「到达率」

公式里的 λ 严格来说是到达率——单位时间进来几个。但在稳态下(进出相等),它也等于吞吐量。这两个词在这本书里可以换着用,但有一个地方必须分清:

当系统过载时,它们不相等。每秒来 1100 个、只能处理 1000 个的时候,到达率是 1100,吞吐是 1000,差出来的 100 个每秒都在往队里堆。此时 Little 定律的前提(稳态)不成立,L 会一直涨,W 会一直涨,公式给不出有限的答案——而这正是它在诚实地告诉你「这不是慢,这是撑不住」。第 21 章会专门讲这件事。

▸ 在现实里

估算一家餐厅的翻台率。路过时数一下店里有多少人(L),站门口数十分钟进去几个(λ),马上就知道平均每桌坐多久。你不需要进去。

看板上的「进行中」列。如果一个团队每周交付 10 个卡片,看板上永远挂着 40 张卡,那么一张卡从开始到完成平均要 4 周——不管站会上大家怎么说「这个很快就好了」。想让交付变快,要么提高吞吐,要么减少同时在做的事,没有第三条路。

线程池大小。「我该开多少个线程」这个问题,Little 定律给的答案是:线程数 = 目标 QPS × 平均每个请求耗时。每秒 500 个请求、每个 40 毫秒,那就需要 500 × 0.04 = 20 个线程一直忙着。开 20 个意味着利用率 100%——所以真实答案要比这个大,大多少,第 9 章会说清楚。

✗ 这个直觉是错的
Little 定律是个近似公式,实际系统那么复杂,它只能给个大概。 它是精确的恒等式,误差为零。你在实测中看到的偏差,来自「观察窗口有限」,不来自公式本身。

这个区别很重要,因为它决定了当数字对不上时你该怀疑谁。如果你量到 L = 150λ = 1200W = 5 小时(而不是 3 小时),那么三个数里至少有一个测错了——最常见的是 λ 只统计了成功的请求而 L 把失败重试的也算进去了,或者 W 的打点漏掉了排队那一段。

换句话说,Little 定律最大的实战价值不是「算出第三个数」,而是当成一个检查器:三个数摆在一起,对不上就说明你的监控在骗你。我在实践中靠这一招抓出过好几次埋点错误。

◇ 结算

B大约 3 小时。W = L / λ = 150 ÷ 1200 = 0.125 天。按一天 24 小时算就是 3 小时。

如果你选了 A 或 D,那说明你的直觉是对的——在绝大多数排队问题里,「不知道分布就答不了」确实是正确的谨慎。这一章的意义正在于告诉你:有且只有这一条例外,而且它是你手上最便宜的一件工具。

A 「数据不够」——对几乎所有别的排队问题都对,唯独对这条不对。Little 定律不需要分布。 C 「大约 8 小时」——大概是按「一个工作日」估的。注意 λ 和 W 的时间单位必须一致:如果订单只在 8 小时工作时间里处理,那 λ 应该按 8 小时算,答案会变成 1 小时。单位对齐是用这条定律最常犯的错。 D 「要看订单分布」——分布决定的是等待时间的方差尾巴(第 4 章、第 5 章),但不影响 L、λ、W 三者之间的这条恒等关系。

这一章的一句话

系统里积压的量、进来的速度、待多久,这三个数只有两个是自由的;第三个是记账记出来的,不是测出来的。

下一章把利用率钉死在 50%——机器有整整一半时间是闲的——然后只拧一个旋钮,看着平均等待从 0.50 一路涨到 5.50 个服务时长。那个旋钮不是速度,不是负载,也不是台数。它是这本书的第二主角,而且它至今在大多数人的监控面板上都没有名字。