限流固定窗口计数

为什么需要

(负责计数、决定放行还是拒绝的组件)要回答一个问题:这个请求者「最近」发了多少个?先要把规则说清楚。本章的图都用同一条规则:每个请求者每 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 秒里放行了0个
到此刻为止,任意 12 秒里最多放行0个

还没开始。按「自动播放」或「下一步」,让「现在」往后走。

代价是什么

固定窗口的好处是省:每个请求者只记一个数,每次只做一次加一。漏洞在两个窗口相接的地方:一个请求者可以在一个窗口快结束时发一批,紧接着在下一个窗口刚开始时再发一批。两个窗口各自都没有超过上限,跨过交界的那 12 秒里放行的却超过了 8 个,最多可达两倍,违背了上面那句保证。Redis(一种常用来存放计数的软件)的官方限流教程也指出了这一点(2026)。

偶尔多放几个也无妨时,固定窗口就够用。YouTube 给开发者的配额每天在太平洋时间零点清零(2026);GitHub 按一小时的窗口计数,每个(服务器发回的消息)都写明当前窗口何时重置(文档未注明日期)。服务器一下子承受不了两倍的请求时,就要换一种数法。

资料来源

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

  1. Build 5 Rate Limiters with Redis: Fixed Window, Sliding Window, Token Bucket, and Leaky BucketWilliam Johnston,Redis,2026-02-26,2026-03-20 更新
  2. Quota CalculatorGoogle for Developers(YouTube Data API),2026-10-15
  3. Rate limits for the REST APIGitHub 文档,未注明日期