第 11 章 · 限流第 2 页,共 9 页
最简单的计数办法是什么,漏洞在哪里?
把时间切成一段一段,每段从零数起,这就是固定窗口。它简单省事,却会在两段相接的地方,放行最多两倍于上限的请求。
为什么需要
(负责计数、决定放行还是拒绝的组件)要回答一个问题:这个请求者「最近」发了多少个?先要把规则说清楚。本章的图都用同一条规则:每个请求者每 12 秒最多 8 个请求。为了在图上看得清楚,这个上限定得很小;真实网站的上限大得多,例如代码网站 GitHub 给登录用户的上限是每小时 5,000 个。
这条规则要保证的是:随便挑出哪一段 12 秒,不管从哪一刻开始,里面放行的请求都不超过 8 个。下面用这句话检验计数的办法。
怎样做
最简单的办法是(fixed window counter):把时间切成首尾相接的 12 秒一段,第 0–12 秒、第 12–24 秒……每一段叫作一个。这里的「窗口」不是窗户,也不是办事的窗口,而是计数所用的一段时间。
每来一个请求,限流器做三件事:读出这个窗口已经放行了几个,判断是否到了 8 个,没到就放行,并写回加一以后的数;到了就拒绝。被拒绝的请求不加进计数。下一个窗口一开始,计数从零数起。本章说到计数,都是这「读出、判断、写回」三步。
在下图里按「自动播放」,让「现在」从第 0 秒走到第 36 秒;也可以选中一个请求,用「提前一格」「推后一格」移动它。
固定窗口:每个窗口最多放行 8 个
先看这里看时间轴上随「现在」移动的浅色带「往前 12 秒」,和图下的读数「此刻往前 12 秒里放行了」。选「挤在交界前后」,按「自动播放」:「现在」越过第 12 秒的交界不久,这个读数就超过了上限 8 个。
- 放行 0 个
- 拒绝 0 个
- 尚未处理 18 个
已选:请求 1 · 第 1 秒 · 尚未处理
用左右方向键选择一项;按住 Shift 再按左右方向键,或者用「提前一格」「推后一格」按钮,移动选中的一项。
所有标记都是同一个请求者发出的请求;时刻挨得太近的,标记上下错开画。放满 8 个的窗口底色变成浅红色。
还没开始。按「自动播放」或「下一步」,让「现在」往后走。
代价是什么
固定窗口的好处是省:每个请求者只记一个数,每次只做一次加一。漏洞在两个窗口相接的地方:一个请求者可以在一个窗口快结束时发一批,紧接着在下一个窗口刚开始时再发一批。两个窗口各自都没有超过上限,跨过交界的那 12 秒里放行的却超过了 8 个,最多可达两倍,违背了上面那句保证。Redis(一种常用来存放计数的软件)的官方限流教程也指出了这一点(2026)。
偶尔多放几个也无妨时,固定窗口就够用。YouTube 给开发者的配额每天在太平洋时间零点清零(2026);GitHub 按一小时的窗口计数,每个(服务器发回的消息)都写明当前窗口何时重置(文档未注明日期)。服务器一下子承受不了两倍的请求时,就要换一种数法。
资料来源
以下资料均于 2026-10-19 访问。