2、常见限流算法详解(上):计数器算法原理、滑动窗口算法原理、两种算法的优缺点对比
在微服务架构中,API Gateway 的限流策略直接决定了后端服务的稳定性与资源利用率。本章将深入剖析两种最基础的限流算法——计数器算法与滑动窗口算法,从原理、实现到优缺点进行系统性对比,为后续参数调优打下坚实的理论基础。
2.1 计数器算法原理
计数器算法(Counter Algorithm)是最简单直观的限流实现方式,其核心思想是:在一个固定的时间窗口内,统计请求总数,一旦超过预设阈值则拒绝后续请求。
2.1.1 算法流程
- 定义时间窗口:设定一个固定的时间长度,例如 1 秒、1 分钟或 1 小时。
- 初始化计数器:在每个时间窗口开始时,将计数器重置为 0。
- 请求到达:每收到一个请求,计数器加 1。
- 阈值判断:如果计数器值 ≤ 阈值,则放行请求;否则直接拒绝。
- 窗口切换:当前时间窗口结束后,自动进入下一个窗口,计数器归零。
典型应用场景:Nginx 的
limit_req_zone 模块、Redis 的 INCR + EXPIRE 实现、单机内存计数器。
2.1.2 核心缺陷:临界突变问题
计数器算法存在一个严重的 “临界突变” 问题:由于时间窗口是固定的,请求可以在窗口边界处集中爆发,导致实际流量远超阈值。例如:
- 设定阈值:100 请求/秒
- 第 1 秒的最后 10ms:涌入 100 个请求
- 第 2 秒的最初 10ms:再次涌入 100 个请求
- 实际在 20ms 内通过了 200 个请求,相当于 10,000 请求/秒的瞬时流量
这种突发流量足以击穿后端服务,而计数器算法对此毫无感知。
2.2 滑动窗口算法原理
滑动窗口算法(Sliding Window Algorithm)是对计数器算法的改进,通过 将固定窗口细分为多个小格子(slot),并随着时间推移动态滑动窗口,从而平滑流量检测,消除临界突变问题。
2.2.1 核心机制
- 窗口划分:将整个时间窗口(如 1 秒)划分为 N 个等长的小格子(如 10 个格子,每个 100ms)。
- 滑动前进:窗口以格子为单位向前滑动,每次滑动丢弃最旧的格子数据,加入最新的格子数据。
- 实时统计:当前窗口的总请求数 = 所有格子计数之和,与阈值比较决定是否限流。
实践建议:格子数量越多,滑动窗口的精度越高,但内存消耗也越大。生产环境中通常将 1 秒划分为 10~20 个格子,在精度与资源之间取得平衡。
2.2.2 算法步骤
- 初始化:创建长度为 N 的环形数组或队列,每个元素初始值为 0。
- 请求到达:计算当前时间所属的格子索引,将该格子计数加 1。
- 窗口滑动:检查当前时间是否已进入下一个格子范围,若是则滑动窗口:将最旧格子计数归零,并更新窗口起始位置。
- 阈值判断:累加当前窗口内所有格子计数,若总和 ≤ 阈值则放行,否则拒绝。
2.3 两种算法优缺点对比
为了帮助你在实际项目中做出正确的技术选型,下面从多个维度对两种算法进行系统性对比。
| 对比维度 | 计数器算法 | 滑动窗口算法 |
|---|---|---|
| 实现复杂度 | 极低,仅需一个计数器 + 时间戳 | 中等,需要环形数组/队列 + 格子管理 |
| 内存开销 | O(1),仅存储一个整型变量 | O(N),N 为格子数(通常 10~20) |
| 流量检测精度 | 低,仅能检测整个窗口的总量 | 高,可检测到格子级别的流量变化 |
| 临界突变防御 | 无,窗口边界处可爆发 2 倍流量 | 强,窗口滑动平滑,无突变窗口 |
| 突发流量容忍 | 窗口内任意时刻均可突发至阈值 | 突发流量被分散到多个格子,更平滑 |
| 适用场景 | 低精度要求、资源受限、简单限流 | 高精度要求、生产环境、微服务网关 |
| 典型实现 | Redis INCR+EXPIRE、Nginx limit_req | Sentinel 滑动窗口、Guava RateLimiter |
选型警告:在微服务 API Gateway 场景中,强烈建议使用滑动窗口算法。计数器算法虽然简单,但其临界突变问题在高并发下极易导致后端服务雪崩。如果必须使用计数器算法,请配合“预热”或“排队”机制进行补偿。
2.4 实战选型建议
基于上述对比,给出以下选型决策树:
- 场景一:单机限流,QPS < 1000,可接受秒级波动
- 推荐:计数器算法
- 理由:实现简单,资源开销极低,性能损耗可忽略
- 场景二:分布式限流,QPS > 1000,要求毫秒级精度
- 推荐:滑动窗口算法(格子数 10~20)
- 理由:消除临界突变,流量曲线平滑,保护后端服务
- 场景三:API Gateway 全局限流,多维度(IP、用户、接口)
- 推荐:滑动窗口算法 + Redis 分片存储
- 理由:支持大规模分布式计数,精度与扩展性兼顾
性能数据参考:在 4C8G 的 API Gateway 节点上,滑动窗口算法(20 格子)的单机吞吐量可达 50,000 QPS,额外延迟 < 0.5ms,完全满足生产环境要求。