漏桶算法
一个底部有洞的桶。水以任意速率倒进去,却只能以稳定的速率从洞里流出。倒得比漏得快,桶就会被填满;再继续倒,就会溢出。
水就是请求,洞就是你的处理速率。
漏桶会把到达的请求放进一个队列,再以固定速率处理它们,所以无论请求到达时有多不均匀,最终打到服务器上的流量都是平滑的。
看着它被填满又排空
容量为五个请求,每秒处理两个,从空桶开始:
| 秒 | 到达 | 排队 | 处理 | 之后队列中 | 被丢弃 |
|---|---|---|---|---|---|
| 1 | 4 | 4 | 2 | 2 | 0 |
| 2 | 4 | 已有3个,加起来共5个 | 2 | 3 | 1 |
| 3 | 0 | 0 | 2 | 1 | 0 |
| 4 | 0 | 0 | 1 | 0 | 0 |
第二秒正是容量吃紧的地方。此时四个请求到达,队列里已经有两个,只有三个能放得下,第八个请求直接被丢弃。
由此可以得出两个特性:
- 输出速率永远不变。 不管到达了八个请求还是一个都没有,都是每秒两个。
- 队列遵循先进先出。 最早到达的请求会最先被处理。
令牌桶说:你想什么时候花掉令牌都行。漏桶说:排队去,我会按我的节奏处理你。
Juno看着它被填满又排空 和之前所有算法相比,最大的不同在于:忙碌时到达的请求不会被拒绝,而是要等待。
只有当队列本身被填满时,请求才会被丢弃,所以漏桶是在吸收一波突发流量,而不是拒绝它。
它的优势和劣势
| 优势 | 劣势 |
|---|---|
| 把突发流量平滑成恒定的输出速率 | 对合理的流量峰值没有任何灵活性 |
| 队列能防止下游过载 | 把系统稳定性置于用户体验之上 |
| 简单易懂,容易实现 | 即便服务器本可以应付,客户端仍要等待 |
| 无论来多少请求,负载都是可预测的 | 延迟会随队列深度增长 |
这些劣势其实是同一种权衡从不同角度看到的结果。漏桶通过让客户端等待来保护服务器,哪怕服务器当时还绰绰有余,它也照样让客户端等。
这适合网络带宽管理、视频流传输,以及需要平稳处理请求的服务器场景——在这些场景里,可预测的速率比对突发流量的快速响应更重要。
Juno它的优势和劣势 这张表里的每一行都源自同一个决定:输出速率是固定的,不会自我调整。
当你需要可预测的负载时,这就是它的优势;而当客户端在等待一个服务器本可以立刻处理的请求时,这就成了它的劣势。
动手试一试
一个容量为5、每秒漏出2个请求的漏桶,从空桶开始。
- 六个请求同时到达。每个请求会怎样?
- 如果第六个到达的请求能被处理,它要等多久才会被处理?
- 同样是这六个请求,但改成每秒到达一个,分散着来。会发生什么?
- 对于一个调用按请求次数收费的支付服务商的接口,哪种算法更合适,为什么?
对照一下你的答案
| # | 答案 | 原因 |
|---|---|---|
| 1 | 五个进入队列,一个被丢弃 | 由于是瞬间涌入,队列能容纳五个,且此时还没来得及漏出任何一个 |
| 2 | 它根本进不了队列 | 被丢弃的正是第六个。第五个是最后一个被接受的,按每秒两个的速率,它要等两秒半 |
| 3 | 全部六个都被处理,没有丢弃,也不用等待 | 每秒一个的到达速率比每秒两个的漏出速率慢,所以队列始终没有堆积起来 |
| 4 | 漏桶 | 瓶颈在下游,而且每次调用都要花钱,所以你需要的是可预测的对外请求速率。用令牌桶的话,一波突发请求会直接变成一波突发扣费 |
第三题是最值得记住的一点:所有这些算法对限额之内的流量都不会做任何处理,它们只在边界处才会显现出作用。
接下来往哪走
一共五种算法,每一种在请求超出限度时,最终都是无声地施加拒绝或等待。
节流(Throttling)让这种等待变得刻意而且可见——在客户端接近限额时逐渐放慢它,而不是等到达到限额才拒绝它,然后把这两种做法整合成一套体系。

