第 11 章 · 限流第 6 页,共 9 页
慢请求占着不放,按次数限得住吗?
按次数限流只管来了多少个,不管每个占多久。限制同时进行的请求数,才管得住慢请求。
为什么需要
(一直开着、专门等别人来要东西的电脑)同时能处理的请求有限,可以想成一排数目固定的处理位置:一个请求开始处理就占住一个,处理完才让出来。下图的百家菜服务器有 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 个位置都空着。
这 36 秒里到达的读者请求,合计平均要等 2.2 秒,最久的要等 5.2 秒。
代价是什么
并发限制管住了占着不走的请求,这是按次数的做不到的。代价是计数必须可靠地减一:请求无论正常结束、中途出错,还是对方断开了连接,都要把名额还回来;漏掉一次,计数就多出一个,越积越多,最后连正常的请求也会被拒绝。
真实的服务常把两种限制一起用。在线支付公司 Stripe 同时运行两种限流器,一种按每秒的请求数,一种按同时进行的请求数(2017);它的文档说,正式收付款时默认最多同时有 50 个进行中的请求(文档未注明日期)。
资料来源
以下资料均于 2026-10-19 访问。