3、限流基础算法(一):固定窗口计数器算法

固定窗口计数器算法是限流领域最直观、最容易实现的算法之一。它将时间划分为固定的窗口(例如 1 秒、1 分钟),在每个窗口内维护一个计数器,当请求到达时计数器加 1;如果计数器超过预设阈值,则拒绝后续请求,直到下一个时间窗口开始,计数器重置。

3.1 算法原理

核心思想:以固定的时间粒度切分流量,在每个粒度内独立计数。算法不关心窗口内的请求分布是否均匀,只关心窗口总请求数是否越界。

固定窗口计数器算法原理 窗口 1 (0~1s) 窗口 2 (1~2s) 窗口 3 (2~3s) 窗口 4 (3~4s) 计数器: 5 计数器: 3 计数器: 5 计数器: 3 阈值=5 说明: 窗口 1 和窗口 3 的请求数达到阈值 5,后续请求(红色点)被拒绝;窗口 2 和窗口 4 的请求数未超限,全部通过。

3.2 实现步骤

固定窗口计数器的实现非常简洁,核心只需要维护一个计数器和一个时间戳。以下是标准实现步骤:

  1. 初始化:设置窗口大小 windowSize(毫秒)和阈值 limit;初始化计数器 counter = 0,记录当前窗口起始时间 windowStart = now()。
  2. 请求到达:获取当前时间 currentTime。
  3. 窗口判断:如果 currentTime - windowStart > windowSize,说明已进入下一个时间窗口,重置 counter = 0,更新 windowStart = currentTime。
  4. 阈值检查:如果 counter < limit,允许请求通过,counter++;否则拒绝请求。

伪代码实现:

class FixedWindowRateLimiter:
    def __init__(self, window_size_ms, limit):
        self.window_size = window_size_ms
        self.limit = limit
        self.counter = 0
        self.window_start = current_time_ms()

    def allow_request(self):
        now = current_time_ms()
        if now - self.window_start > self.window_size:
            self.counter = 0
            self.window_start = now
        if self.counter < self.limit:
            self.counter += 1
            return True
        return False

3.3 优缺点分析

维度 说明
优点
  • 实现简单:只需一个计数器和一个时间戳,代码量极少。
  • 内存占用低:仅需存储两个变量,适合嵌入式或边缘设备。
  • 性能极高:每次请求仅需 O(1) 时间复杂度的判断和整数运算。
  • 易于理解:概念直观,团队沟通成本低。
缺点
  • 临界流量突刺:窗口边界处可能出现双倍流量。例如窗口大小为 1 秒、阈值为 5,若 0.9~1.0s 内来了 5 个请求,1.0~1.1s 内又来了 5 个请求,则 0.2 秒内实际通过了 10 个请求,远超阈值。
  • 流量不平滑:无法控制窗口内的请求速率,允许窗口前期集中消费所有配额。
  • 时间精度敏感:若系统时钟回拨或窗口边界处理不当,可能导致限流失效。
固定窗口临界突刺问题 窗口 1 (0~1s) 窗口 2 (1~2s) 窗口边界突刺 0.95s~1.05s 内通过 10 个请求 临界突刺问题: 窗口 1 末尾和窗口 2 开头各允许 5 个请求,但实际在极短时间(约 0.1s)内通过了 10 个请求,导致后端瞬时压力翻倍。

3.4 适用场景

固定窗口计数器算法虽然存在临界突刺问题,但在以下场景中仍然非常实用:

场景 适用原因
粗粒度限流 对时间窗口内的请求总数有硬性上限要求,不关心窗口内的瞬时波动。例如:每分钟最多允许 1000 次 API 调用。
资源预算控制 用于控制每日/每小时的资源消耗总量,如云服务配额、短信发送量、存储写入次数。
原型验证 在项目早期快速实现限流功能,后续再替换为更平滑的算法(如滑动窗口、令牌桶)。
低并发系统 系统 QPS 较低(如 < 100),临界突刺的影响在可接受范围内。
边缘设备/嵌入式 内存和计算资源受限,无法承载复杂算法。

实践建议:在生产环境中,如果选择固定窗口算法,建议将窗口大小设置为业务可接受的最小粒度(例如 100ms 而非 1s),以降低突刺窗口的绝对时长。同时配合后端服务的熔断机制,形成双层保护。

3.5 与后续算法的对比

固定窗口计数器是限流算法家族的基石。理解它的优缺点,有助于后续学习更高级的算法:

对比维度 固定窗口 滑动窗口日志 令牌桶 漏桶
实现复杂度 ★☆☆☆☆ ★★★☆☆ ★★☆☆☆ ★★☆☆☆
内存占用 极低 较高 低 低
临界突刺 有 无 无 无
流量平滑度 差 较好 好 最好
突发处理 不支持 不支持 支持 不支持