常见限流策略对比
一、固定窗口限流(计数器限流)
核心原理:将时间划分为固定长度的窗口(如 1 分钟 1 个窗口),每个窗口内维护请求计数器,达到阈值则拒绝请求,窗口切换时重置计数器。比如 “1 分钟内最多允许 100 次请求”,第 61 秒的请求会进入新窗口重新计数。
优点:实现极简单(用 Redis 的 INCR+EXPIRE 即可),性能开销低,适合对精度要求不高的场景。缺点:存在 “窗口边缘突发流量” 问题 —— 比如窗口 1 最后 1 秒和窗口 2 第 1 秒各接收 100 次请求,2 秒内实际触发 200 次请求,远超阈值,可能压垮系统。适用场景:非核心接口(如日志上报、非实时查询),或对流量波动不敏感的内部系统。
二、滑动窗口限流
核心原理:在固定窗口基础上,将大窗口拆分为多个小格子(如 1 分钟窗口拆分为 60 个 1 秒小格子),每次请求时 “滑动” 移除超出窗口范围的小格子,统计剩余小格子的总请求数。比如 10 秒窗口拆分为 10 个 1 秒格子,第 11 秒时移除第 1 秒的格子,统计 2-11 秒的总请求数。
优点:解决固定窗口的临界值问题,限流精度更高;通过 Redis+Lua 脚本可实现分布式环境下的原子操作,避免并发计数误差。缺点:实现复杂度高于固定窗口,需维护多个小格子的计数,Redis 存储成本略有增加(需存储每个小格子的时间戳和计数)。适用场景:核心业务接口(如订单创建、支付回调),对流量平稳性要求高的场景,尤其适合分布式系统。
三、漏桶算法
核心原理:类比 “漏水的桶”—— 请求像水流一样进入桶中,桶以固定速率向外 “漏水”(处理请求),若桶满则新请求溢出(拒绝)。比如桶容量 100,漏水速率 10 次 / 秒,即使瞬间涌入 200 次请求,也只会以 10 次 / 秒的速率处理,多余 100 次直接拒绝。
优点:强制请求按固定速率处理,能平滑输出流量,避免突发请求冲击下游系统(如数据库),适合保护后端资源。缺点:灵活性低,无法应对 “短时间内的合理峰值”—— 比如平时请求量低,偶尔 1 秒内有 50 次合理请求,但桶速率仅 10 次 / 秒,会导致 40 次请求被误拒,影响用户体验。适用场景:下游资源处理能力固定的场景(如数据库写入、第三方接口调用),或需要严格控制输出速率的链路(如 API 网关转发请求到微服务)。
四、令牌桶算法
核心原理:系统以固定速率(如 10 个 / 秒)向桶中放入令牌,请求到来时需从桶中获取 1 个令牌才能被处理,无令牌则拒绝或排队。桶有最大容量,令牌满时不再新增。比如桶容量 50,生成速率 10 个 / 秒,若 10 秒内无请求,桶会累积 50 个令牌,此时突然涌入 50 次请求,可一次性处理,之后恢复 10 次 / 秒的速率。
优点:兼顾 “限流” 和 “灵活性”—— 既限制长期平均速率,又允许短时间内的合理峰值请求(利用累积的令牌),用户体验更优;可通过调整令牌生成速率动态适配系统负载。缺点:实现复杂度高于前两种策略,需维护令牌生成计时器和桶容量,分布式环境下需确保令牌生成的一致性(如用 Redis 的 Sorted Set 存储令牌)。适用场景:用户交互类接口(如商品详情查询、用户登录),需要平衡 “限流严格性” 和 “峰值处理能力” 的场景,也是 API 网关常用的限流算法。
五、总结:如何选择限流策略?
- 看精度需求:核心接口用滑动窗口 / 令牌桶,非核心接口用固定窗口;
- 看下游承受能力:若下游是数据库等 “慢资源”,用漏桶强制平稳流量;若下游能承受短期峰值,用令牌桶提升灵活性;
- 看实现成本:中小团队优先选滑动窗口(Redis+Lua 易落地),大型团队可基于令牌桶做定制化开发(如结合监控动态调整速率)。