3. 常见限流算法详解(上):计数器算法、滑动窗口算法、漏桶算法

在金融低延迟场景中,限流算法的选择直接决定了系统的吞吐上限、响应抖动以及资源利用率。本章深入剖析三种经典限流算法的核心原理、数学特性、优劣势及适用边界,帮助架构师在低延迟与高精度之间做出合理权衡。

3.1 计数器算法(Counter Algorithm)

3.1.1 原理

计数器算法是最直观的限流实现。在固定时间窗口(如 1 秒)内维护一个计数器,每次请求到达时计数器加 1;当计数器达到预设阈值时,后续请求被拒绝;窗口结束后计数器重置为零。

核心逻辑伪代码:
// 固定窗口计数器限流
long currentTime = System.currentTimeMillis() / 1000; // 按秒分桶
if (currentTime != lastWindowStart) {
    counter = 0;
    lastWindowStart = currentTime;
}
if (counter < threshold) {
    counter++;
    return ALLOW;
} else {
    return REJECT;
}

3.1.2 优缺点

维度 说明
优点 实现极简,仅需一个计数器和时间戳;内存占用 O(1);计算延迟为纳秒级,适合高频调用。
缺点 存在严重的窗口边界突刺问题:在窗口末尾和下一窗口开头,允许瞬间两倍阈值的流量通过,导致限流失效。
适用场景 对精度要求不高、允许短时毛刺的非核心业务;或作为前置快速过滤层。
金融避坑: 在交易峰值秒杀场景中,计数器算法的边界突刺可能让瞬时 QPS 翻倍,直接击穿下游数据库连接池。不建议用于核心交易链路。

3.1.3 适用场景

  • 非关键路径的日志上报、监控指标采集。
  • 客户端 SDK 侧的简易限流。
  • 与其它算法组合使用,作为第一道粗粒度过滤。
计数器算法边界突刺示意图 计数器算法:窗口边界突刺问题 窗口 1 计数器 = 100 (阈值) 请求被拒绝 窗口 2 计数器 = 100 (阈值) 请求被拒绝 边界突刺 窗口末尾 + 窗口开头 = 瞬时 2 倍流量 T T+1s T+2s

3.2 滑动窗口算法(Sliding Window Algorithm)

3.2.1 原理

滑动窗口算法将固定窗口细分为多个小格(如 1 秒分为 10 个 100ms 的格子),每个格子独立计数。窗口随时间向前滑动,每次请求统计当前时间点所在窗口内所有格子的累计值。格子越细,精度越接近真正的匀速限流。

精度与性能的权衡: 格子数量越多,限流精度越高,但内存占用和计算开销也线性增长。金融低延迟场景通常选择 10~20 个格子,在精度与性能之间取得平衡。

3.2.2 优缺点

维度 说明
优点 消除了固定窗口的边界突刺问题;精度可通过调整格子数量灵活控制;实现相对简单。
缺点 内存占用 O(n),n 为格子数;每次请求需遍历窗口内所有格子求和,CPU 开销高于计数器算法;格子数过多时延迟增加。
适用场景 需要平滑限流、对边界突刺敏感的核心 API;如交易下单、风控校验。

3.2.3 适用场景

  • 金融核心交易链路的限流保护。
  • 对流量毛刺容忍度低的实时报价系统。
  • 需要精确控制每秒请求数的网关层。
滑动窗口算法结构图 滑动窗口算法:细粒度格子统计 格1 格2 格3 格4 格5 格6 格7 格8 格9 格10 当前滑动窗口 (1s) 窗口内总计数 = 格3 + 格4 + 格5 + 格6 + 格7 + 格8 每 100ms 窗口向右滑动一格,丢弃最左格,加入新格 滑动方向 →

3.3 漏桶算法(Leaky Bucket Algorithm)

3.3.1 原理

漏桶算法将请求视为水滴,先注入一个固定容量的桶中,桶底部以恒定速率向外漏水(处理请求)。当桶满时,新请求被丢弃。漏桶强制输出速率恒定,无论输入流量如何波动。

关键参数:
  • 桶容量(capacity): 最大允许的积压请求数,对应系统能容忍的最大突发。
  • 漏水速率(leakRate): 每秒处理的请求数,即系统的恒定吞吐率。
  • 当前水量(water): 桶中积压的请求数,随时间以漏水速率减少。

3.3.2 优缺点

维度 说明
优点 输出速率绝对平滑,无任何突刺;能有效吸收突发流量;实现简单,适合硬件和底层网络。
缺点 无法应对突发流量带来的低延迟要求——即使桶未满,请求也需排队等待;对短时爆发性业务不友好;参数调优困难。
适用场景 需要严格平滑输出的场景,如数据库写入限流、消息队列生产速率控制。

3.3.3 适用场景

  • 数据库连接池的写入速率控制,防止打盘 I/O 打满。
  • 日志采集与传输,避免后端存储被突发流量冲垮。
  • 硬件设备(如网卡、FPGA)的流量整形。
漏桶算法原理图 漏桶算法:恒定输出速率 当前水量 (积压请求) 容量 请求流入 恒定速率流出 桶满则丢弃

3.4 三种算法对比总结

特性 计数器算法 滑动窗口算法 漏桶算法
输出平滑度 差(有边界突刺) 较好(取决于格子数) 极好(绝对恒定)
内存开销 O(1) O(n) O(1)
计算延迟 极低(纳秒级) 低(微秒级) 极低(纳秒级)
突发吸收能力 弱 中等 强(但增加排队延迟)
低延迟友好度 高 高 低(排队引入等待)
金融推荐度 ⭐(非核心) ⭐⭐⭐⭐(核心交易) ⭐⭐⭐(后端保护)