花拾录
← 返回知识库

限流算法选型:计数器、漏桶与令牌桶在接口层的落地差异

后端开发AI2026/09/240 阅读0 评论

为什么接口需要限流?

限流是保护系统免受过载请求冲击的常用手段。无论是防止恶意爬虫、应对突发流量,还是保障核心接口的稳定性,选择合适的限流算法都至关重要。本文对比计数器、漏桶和令牌桶三种算法在接口层的落地差异,帮助你做出合理选型。

1. 固定窗口计数器

原理:将时间划分为固定窗口(如1秒),每个窗口内维护一个计数器。请求到达时计数器加1,超过阈值则拒绝,窗口结束后计数器清零。

优点:实现简单,内存占用小,适合单机或对精度要求不高的场景。

缺点:存在“临界问题”。例如限制每秒100次,若在窗口最后10毫秒涌入100次,下一个窗口开始又涌入100次,实际2个窗口间可能通过200次请求,超出预期。

落地建议:

  • 使用 Redis 的 INCR + EXPIRE 实现分布式计数器。
  • 注意原子性,可用 Lua 脚本保证。
  • 适用于对突发流量不敏感的粗粒度限流。

2. 滑动窗口计数器

原理:固定窗口的改进版,将大窗口拆分为多个小窗口(如1秒拆成10个100毫秒),统计最近N个小窗口的总请求数。

优点:缓解临界问题,精度更高。

缺点:需要存储更多状态,内存消耗增加。

落地建议:

  • 可用 Redis 的 ZSET 或 List 存储时间戳,但需注意性能。
  • 适合对平滑性有一定要求的 API 网关。

3. 漏桶算法

原理:请求像水一样注入漏桶,桶以恒定速率漏水(处理请求)。桶满则拒绝新请求。

优点:强制恒定输出速率,能平滑突发流量,保护下游服务。

缺点:无法应对合理的突发流量(即使系统有空闲资源),且需要队列缓冲,增加延迟。

落地建议:

  • 常用于流量整形,如 Nginx 的 limit_req 模块即基于漏桶。
  • 实现时可用队列 + 定时消费,或令牌桶模拟。

4. 令牌桶算法

原理:以恒定速率向桶中添加令牌,桶有容量上限。请求到达时需获取令牌,无令牌则拒绝或等待。

优点:允许一定程度的突发流量(桶中积累的令牌可一次性使用),同时限制平均速率。

缺点:实现稍复杂,需维护令牌数量和时间戳。

落地建议:

  • 常用实现:Guava RateLimiter(单机)、Redis + Lua(分布式)。
  • 适合需要兼顾平均速率和突发能力的接口,如 API 限流。

选型对比

算法突发流量平滑度实现复杂度典型场景
固定窗口允许但可能超限差低简单计数
滑动窗口较平滑较好中API 网关
漏桶严格限制好中流量整形
令牌桶允许一定突发较好中高通用限流

落地注意事项

  1. 分布式一致性:多实例部署时,需使用 Redis 等集中存储,并保证原子性。
  2. 性能开销:限流本身不应成为瓶颈,避免频繁网络往返,可考虑本地缓存 + 集中同步。
  3. 降级策略:限流触发后,应返回友好错误(如 429 Too Many Requests),并记录日志。
  4. 动态调整:阈值最好可配置,便于根据业务变化调整。

总结

  • 若只需简单防护,固定窗口计数器足够。
  • 若需平滑流量且允许突发,令牌桶是首选。
  • 若需严格限制输出速率,漏桶更合适。
  • 滑动窗口是固定窗口与漏桶之间的折中。

实际选型应结合业务特点、精度要求和系统架构,必要时可组合使用。

评论(0)

  • 还没有评论,来抢沙发~

相关文章