限流同时进行的请求

为什么需要

(一直开着、专门等别人来要东西的电脑)同时能处理的请求有限,可以想成一排数目固定的处理位置:一个请求开始处理就占住一个,处理完才让出来。下图的百家菜服务器有 6 个位置。智能厨具公司新增了「导出全部菜谱」的请求,每 2 秒发 1 个,也就是每 12 秒 6 个,没有超出每 12 秒 8 个的上限。可是导出很慢,一个可能要处理 20 秒。

同时在处理的请求数,大约等于每秒到达的个数乘以每个请求停留的时间(排队论里的利特尔法则,1961)。每秒 0.5 个、每个 20 秒,平均要同时占住 10 个位置,比服务器的 6 个还多,普通读者的请求只能排队。

怎样做

办法是(concurrency limit):限制同一时刻已经被服务器接下、还没有处理完的请求有多少个(包括正在处理的和排队等着处理的),而不是一段时间里来了多少个。请求被接下时计数加一,处理完时减一;新的请求到来时,如果这个请求者已经有 2 个这样的请求,就拒绝它。

在下图里调节导出要处理多久,再打开并发限制。普通读者的请求随机到达,平均每秒 2 个,每个约处理 1 秒。

慢请求占满处理位置

先看这里先看 6 个处理位置。把导出调到「20 秒」,按「直接跳到第 20 秒」:6 个位置全被导出请求占住,十几个读者的请求在排队;再打开并发限制,多出来的导出被拒绝,读者几乎不用等。

每个导出请求要处理
并发限制
  • 放行 0 个
  • 排队 0 个
  • 拒绝 0 个
  • 尚未处理 18 个

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

用左右方向键选择一项。

导出请求一开始处理就标成放行;还在等空位的标成排队。

现在:尚未开始

服务器的 6 个处理位置尚未开始

  • 位置 1空闲
  • 位置 2空闲
  • 位置 3空闲
  • 位置 4空闲
  • 位置 5空闲
  • 位置 6空闲

尚未开始:6 个位置都空着。

此刻占用的处理位置0个,共 6 个
到此刻为止,读者的请求平均等了0 秒
到此刻为止到达的导出请求:已开始处理 · 还在排队 · 被拒绝0 · 0 · 0

这 36 秒里到达的读者请求,合计平均要等 2.2 秒,最久的要等 5.2 秒。

代价是什么

并发限制管住了占着不走的请求,这是按次数的做不到的。代价是计数必须可靠地减一:请求无论正常结束、中途出错,还是对方断开了连接,都要把名额还回来;漏掉一次,计数就多出一个,越积越多,最后连正常的请求也会被拒绝。

真实的服务常把两种限制一起用。在线支付公司 Stripe 同时运行两种限流器,一种按每秒的请求数,一种按同时进行的请求数(2017);它的文档说,正式收付款时默认最多同时有 50 个进行中的请求(文档未注明日期)。

资料来源

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

  1. A Proof for the Queuing Formula: L = λWJohn D. C. Little,Operations Research,1961
  2. Scaling your API with rate limitersPaul Tarjan,Stripe,2017-03-30
  3. Rate limitsStripe 文档,未注明日期