第 4 章:设计限流器
引言
本章探讨限流器的设计与实现。限流器用于控制客户端或服务发送的流量速率,对于防止滥用、降低成本和保持服务器资源稳定至关重要。例如限制发帖、创建账号和领取奖励的频率。
限流的好处
- 防止 DoS 攻击: 拦截过量调用,避免资源耗尽。
- 降低成本: 限制不必要的请求,减少服务器开支。
- 防止过载: 过滤过量请求,稳定服务器性能。
第 1 步:理解问题
主要功能
- 在服务端对 API 限流。
- 支持多条限流规则。
- 适用于分布式环境中的大规模系统。
- 可实现为独立服务或应用内代码。
- 用户被限流时给予提示。
要求
- 准确限制请求速率。
- 尽量降低延迟。
- 减少内存占用。
- 支持分布式部署。
- 清晰处理异常。
- 具备高容错性。
第 2 步:高层设计
部署位置选择
<img src="/images/chapter-04/rate_limiter_architecture.png" alt="限流中间件架构" width="550" />
- 客户端实现: 客户端可能被滥用,因此不可靠。
- 服务端实现: 控制力和可靠性较强,通常更合适。
- 中间件(API 网关): 便于集成限流的灵活选择。
部署位置的选择原则
- 评估当前技术栈,选择高效方案。
- 按业务需求选择合适算法。
- 采用微服务架构时,可使用 API 网关。
- 资源有限时,可选择商业产品。
第 3 步:限流算法
1. 令牌桶

- 原理: 以固定速率向桶中加入令牌,每个请求消耗一个令牌。
- 参数: 桶容量与令牌补充速率。
- 优点: 容易实现、节省内存、允许突发流量。
- 缺点: 需要仔细调整参数。
2. 漏桶

原理: 使用 FIFO 队列,以固定速率处理请求。
优点: 节省内存、输出速率稳定。
缺点: 突发流量可能导致后续请求延迟。
3. 固定窗口计数器

原理: 将时间划分为固定区间,通过计数器限制请求数。
优点: 简单,对特定场景效率高。
缺点: 窗口边界处的流量突增可能突破限制。
时间窗口边界处突然涌入的流量,可能使通过的请求数超过配额。

4. 滑动窗口日志

- 原理: 记录请求时间戳,以维护滚动时间窗口。
- 优点: 限流准确。
- 缺点: 内存消耗较高。
5. 滑动窗口计数器

- 原理: 结合固定窗口与滑动日志的方法,平滑流量峰值。
- 优点: 节省内存,能处理突发流量。
- 缺点: 由于采用近似计算,限制未必完全严格。
高层架构

- 数据存储: 使用内存缓存(如 Redis)快速操作计数器。
- 流程:
- 客户端向中间件发送请求。
- 中间件检查 Redis 中的计数器。
- 根据限额处理或拒绝请求。
进阶注意事项
分布式环境
- 挑战: 竞态条件与同步问题。
- 解决方法: 使用锁、Redis Lua 脚本或有序集合;通过集中式数据存储进行同步。
性能优化
- 采用多数据中心部署降低延迟。
- 使用最终一致性模型处理同步。
监控
- 定期分析数据,确认算法有效性,并按需要调整规则。