本文目录导读:

高频访问的限流管控是保障系统稳定性和公平性的核心手段,以下是常见的限流策略、算法及其实现方案,帮助你根据业务场景选择合适的方法:
核心限流策略
固定窗口计数器
- 原理:将时间划分为固定窗口(如1秒),统计窗口内请求数,超过阈值则拒绝。
- 优点:实现简单,内存占用小。
- 缺点:窗口边界可能出现“双倍流量”冲击(如窗口切换瞬间)。
- 适用场景:对临界突发不敏感的低精度场景。
滑动窗口日志
- 原理:记录每个请求的时间戳,滑动窗口内统计最近N秒的请求数。
- 优点:平滑边界流量,避免窗口切换突变。
- 缺点:需存储大量时间戳,内存消耗高。
- 适用场景:需精确控制流量峰值的场景。
令牌桶算法
- 原理:以固定速率向桶内添加令牌,请求需获取令牌才能通过;桶内最多存N个令牌(应对突发)。
- 优点:允许突发流量,性能优秀(原子操作)。
- 缺点:需维护令牌生成器和桶状态。
- 适用场景:API网关、微服务限流(如
golang.org/x/time/rate)。
漏桶算法
- 原理:请求以固定速率流出(处理),溢出则丢弃。
- 优点:强制平滑流量,适合保护下游处理能力固定的服务。
- 缺点:无法应对突发流量,可能增加延迟。
- 适用场景:数据库连接池、消息队列消费限流。
分层限流架构(推荐方案)
| 层 | 技术选型 | 作用 | 典型配置 |
|---|---|---|---|
| 网络层 | Nginx / LVS | 全局入口限流 | limit_req_zone + 令牌桶 |
| 应用层 | Redis + Lua | 分布式限流(精准) | 滑动窗口、令牌桶 |
| 代码层 | 本地缓存+原子类 | 单机QPS保护 | Guava RateLimiter(令牌桶) |
关键实现方案
单机限流(Guava RateLimiter)
// 创建令牌桶,每秒生成100个令牌
RateLimiter limiter = RateLimiter.create(100.0);
// 尝试获取1个令牌(非阻塞)
if (limiter.tryAcquire()) {
// 处理请求
} else {
// 返回429 Too Many Requests
}
分布式限流(Redis + Lua)
-- 滑动窗口限流Lua脚本
local key = KEYS[1]
local now = tonumber(ARGV[1]) -- 当前时间戳(毫秒)
local window = tonumber(ARGV[2]) -- 窗口大小(毫秒)
local limit = tonumber(ARGV[3]) -- 窗口内最大请求数
local current_count = redis.call('ZCOUNT', key, now - window, now)
if current_count < limit then
redis.call('ZADD', key, now, now) -- 添加当前请求
redis.call('EXPIRE', key, window / 1000) -- 设置过期时间
return 1 -- 允许通过
else
return 0 -- 拒绝请求
end
调用示例:
EVAL script 1 user:api:login 1680000000123 1000 10(1秒内最多10次登录请求)
常见限流场景与配置
| 场景 | 限流粒度 | 算法 | 阈值示例 | 备注 |
|---|---|---|---|---|
| API接口 | 用户+接口 | 滑动窗口 | 1秒10次,1小时100次 | 需考虑幂等性 |
| 登录接口 | IP+账号 | 固定窗口+验证码 | 5次/分钟(IP),3次/分钟(账号) | 防止暴力破解,需要CAPTCHA |
| 爬虫/抓取 | IP | 令牌桶 | 100次/秒 | 需配合User-Agent + 签名验证 |
| 数据库连接 | 连接池级别 | 漏桶 | 200次/秒 | 防止连接池耗尽 |
| 消息队列消费 | 消费者实例 | 漏桶 | 1000条/秒 | 防止消费者过载 |
高级限流策略
自适应限流(Adaptive Rate Limiting)
- 原理:根据后端负载动态调整限流阈值(如CPU使用率>80%自动降级)。
- 实现:结合
Hystrix熔断+降级,或自定义负载感知算法。 - 代码示例:
int dynamicLimit = (int) (baseLimit * (1 - cpuUsage)); // CPU越高限制越严格 rateLimiter.setRate(dynamicLimit);
优先级限流
- 原理:对VIP用户、核心业务分配更高限流配额。
- 实现:给不同用户组分配不同令牌桶,或使用加权公平队列(WFQ)。
细粒度限流(热点限流)
- 场景:对特定商品ID、视频ID等热点资源单独限流。
- 方案:使用Redis的
Hash结构存储热点资源的计数器,Lua保证原子性。
限流效果验证与调优
- 压测工具:
wrk、JMeter、Locust - 监控指标:
- 限流率(Rejected/Total)
- 平均延迟(允许通过请求的P99)
- 请求积压长度
- 常见问题:
- 限流失效:检查Redis连接断开后是否降级为本地限流。
- 过度限流:定期根据业务流量曲线调整阈值(如促销日翻倍)。
- 误差累积:分布式场景同步时间需通过NTP校准。
实际案例:电商秒杀系统限流
架构设计:
- Nginx层:限制每个IP每秒最多5次请求,使用令牌桶。
- Redis滑动窗口:全局限制每秒1000次秒杀请求。
- 应用层本地限流:每个服务实例处理最多50并发(漏桶)。
- 熔断降级:若后端库存服务延迟>500ms,直接返回“抢购火爆”。
限流后处理:
- 直接返回HTTP 429状态码 +
Retry-After头。 - 客户端展示“请求过于频繁,请稍后再试”提示。
- 降级至静态页面或读旧缓存。
- 单机/小流量:优先使用本地限流(Guava、RateLimiter),性能最优。
- 分布式/大流量:使用Redis+Lua实现全局一致性,注意Redisson等成熟客户端。
- 关键原则:限流必须分层部署(网络->应用->代码),结合业务特征选择算法,并始终提供友好的限流反馈(状态码+等待时间)。
如果涉及全球部署,请考虑CDN层限流(如CloudFlare的Rate Limiting规则)或使用分布式计数器(如Redis Cluster+一致性哈希)。