限流漏桶

为什么需要

上一页的容许一下子来一批,可有些服务一点集中也承受不了。百家菜给智能厨具公司开了「菜谱同步」服务:厨具公司的 App 隔一段时间把百家菜新增和改过的菜谱取回去,让自己存的那份与百家菜一致,这叫同步。处理同步的程序每 1.5 秒只能做 1 个,厨具公司却常常一下子发来好几个。拒绝它们,对方得自己再试;让它们排队、每 1.5 秒放进去一个,对方只是多等一会儿,每个请求最后都能完成。

怎样做

(leaky bucket)的名字来自一个设想:水从上面倒进一只底部有孔的桶,从孔里以固定的速度漏出去,桶满了就溢出。换成请求:请求进桶,桶按固定的速度把请求放出去,桶满了,新来的被拒绝。这个比喻有一处不成立:限流器的桶里装的不是水,要么排着真实的请求,要么只是一个数,取决于下面哪一种用法。

  • 排队:桶就是一条队伍。来得不急的请求立即放行:桶是空的、出口也空着时,来的请求立即放出去,不用排队。来得太急的进桶排队,每 1.5 秒放出一个;桶里已经排满 8 个时,新来的被拒绝。
  • 只计量:桶里不真的排着请求,只记一个「水位」。水位按固定的速度下降,每放行一个请求升高 1;升高以后不超过容量就立即放行,超过就立即拒绝。这样用的漏桶与令牌桶效果完全相同:水位相当于用掉的令牌,桶里剩下的空间相当于攒下的令牌。

下图里的请求不规则地涌来,到达的时刻每次打开页面都一样。调节流出的速度和桶的容量,在两种用法之间切换,对照三种结果:立即放行、排队、拒绝。

漏桶:看超出速度的请求是排队还是被拒绝

先看这里按「自动播放」看时间轴:来得太急的请求标成沙漏,轮到它从桶底放出时变成放行;排满 8 个以后,新来的被拒绝。再看对照表:「令牌桶」和「漏桶 · 只计量」两行的数字一个不差。

用法
流出速度
桶的容量
漏桶 · 排队尚未开始

流入请求从上面进桶,桶满就拒绝

流出每 1.5 秒放出 1 个,交给菜谱同步服务

现在排着 0 个,最多 8 个

 

用左右方向键前后移动时间,Home 回到开头,End 跳到最后。

  • 放行 0 个
  • 排队 0 个
  • 拒绝 0 个
  • 尚未处理 23 个

已选:请求 1 · 第 0.5 秒 · 尚未处理

用左右方向键选择一项。

时刻挨得太近的请求,标记上下错开画。

现在:尚未开始
六种办法各让多少请求立即放行、排队或被拒绝
办法立即放行排队后放行拒绝任意 12 秒里最多放行平均多等每个请求者要记住
固定窗口1607120 秒1 个数
滑动窗口 · 记下每一次的时间1301080 秒最多 8 个时刻
滑动窗口 · 按比例估算140990 秒2 个数
令牌桶1904140 秒2 个数:令牌数和时刻
漏桶 · 只计量1904140 秒2 个数:水位和时刻
漏桶 · 排队515383.8 秒排着的请求本身,最多 8 个

六种办法设得一样宽松:长期平均都是每 1.5 秒 1 个,一次最多都能放行 8 个(窗口按「每 12 秒最多 8 个」计),所以差别来自办法本身。但看「任意 12 秒里最多放行」:令牌桶和只计量的漏桶有一段放行了接近两倍,排队的漏桶放出去的从不超过 8 个。

代价是什么

本章的计数办法到这里都讲完了,图下的对照表把它们放在同一组请求上。排队保护了后面的服务:放出去的请求永远匀速。代价是等待,排在后面的要多等好几个 1.5 秒;队伍也有长度,排满了照样拒绝。所以排队适合「菜谱同步」这类晚一点完成也无妨的事,不适合要立即答复的操作,微软的云服务 Azure 的设计指南也这样提醒(2026)。只计量的用法立即答复,代价是超出的请求被直接拒绝,对方要自己再试。

真实的产品各用一种。常用的网站服务器软件 NGINX 负责限流的那部分按漏桶的办法工作:默认允许的突发数是 0,超出速度的请求直接被拒绝;设了允许的突发数以后,超出的请求先排队、延后处理;再打开一个「不延后」的选项,才改成立即处理(文档未注明日期)。电商平台 Shopify 给开发者的(程序向它要数据时所用的一份请求清单,不是插充电线的接口)大多数也按漏桶计数,桶满时直接拒绝,属于只计量的用法(文档未注明日期)。名字不同,效果多半等价;差别在于超出的请求被拒绝还是排队,以及速度和突发上限的设定。

资料来源

以下资料均于 2026-10-19 访问。

  1. Rate Limiting patternMicrosoft Azure 架构中心,2026-06-08
  2. Module ngx_http_limit_req_moduleNGINX,未注明日期
  3. Shopify API limitsShopify,未注明日期