一、核心限流算法原理与实现
以下是五种主流限流算法的实现逻辑及特点分析:
1. 计数器算法(Fixed Window Counter)
- 原理
在固定时间窗口(如1秒)内统计请求数,超过阈值则限流。例如,1秒内允许100次请求,窗口滑动后重置计数器。 - 实现
AtomicInteger counter = new AtomicInteger(0);
long windowStart = System.currentTimeMillis();
public boolean allowRequest() {
long now = System.currentTimeMillis();
if (now - windowStart > 1000) { // 窗口重置
counter.set(0);
windowStart = now;
}
return counter.incrementAndGet() <= 100;
}
- 特点
-
- ✅ 优点:实现简单,内存消耗低。
- ❌ 缺点:窗口边界处可能出现突发流量(如两个窗口切换时瞬时流量翻倍)。
2. 滑动窗口计数器(Sliding Window Counter)
- 原理
将固定窗口细分为多个小片段(如每100ms一个片段),动态滑动统计当前窗口内的总请求数。 - 实现
使用队列或环形数组记录每个片段的请求数,滑动时清理过期片段并累加当前窗口的请求量。 - 特点
-
- ✅ 优点:缓解固定窗口的临界问题,流量控制更平滑。
- ❌ 缺点:实现复杂度高,存储和计算开销随窗口细分程度增加而增长。
3. 漏桶算法(Leaky Bucket)
- 原理
请求像水一样倒入桶中,桶以固定速率“漏水”(处理请求)。若桶满,新请求被丢弃。 - 实现
ArrayBlockingQueue<Integer> bucket = new ArrayBlockingQueue<>(capacity);
public boolean allowRequest() {
return bucket.offer(1); // 桶满则返回false
}
后台线程按固定速率从桶中取出请求处理。
- 特点
-
- ✅ 优点:严格限制流出速率,平滑流量。
- ❌ 缺点:无法应对突发流量(突发请求需排队等待)。
4. 令牌桶算法(Token Bucket)
- 原理
系统以固定速率向桶中添加令牌,请求需消耗令牌。桶有容量上限,允许突发流量消耗积累的令牌。 - 实现(Guava RateLimiter示例)
RateLimiter limiter = RateLimiter.create(5.0); // 每秒生成5个令牌
if (limiter.tryAcquire()) {
// 处理请求
}
- 特点
-
- ✅ 优点:支持突发流量,平滑与灵活性兼顾。
- ❌ 缺点:实现较复杂,需维护令牌生成和消耗逻辑。
5. 分布式限流算法
- 原理
在分布式系统中,通过Redis等中间件实现跨节点限流。常见方案包括:
-
- Redis + Lua:原子性操作保证计数一致性。
- 滑动窗口日志:记录每个请求时间戳,统计时间窗口内总数。
- 实现示例(Redis Lua脚本)
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = redis.call('INCR', key)
if current == 1 then
redis.call('EXPIRE', key, 1) -- 1秒过期
end
return current > limit
- 特点
-
- ✅ 优点:支持全局限流,适合高并发分布式场景。
- ❌ 缺点:依赖Redis性能,存在网络延迟风险。
二、算法对比与选型建议
算法 |
实现复杂度 |
内存消耗 |
突发流量支持 |
平滑度 |
适用场景 |
固定窗口计数器 |
低 |
低 |
不支持 |
差 |
简单低频限流(如单机API计数) |
滑动窗口计数器 |
中 |
中 |
部分支持 |
中 |
常规API限流(需较高精度) |
漏桶算法 |
中 |
中 |
不支持 |
极佳 |
需严格恒定速率的场景(如支付系统) |
令牌桶算法 |
高 |
高 |
支持 |
佳 |
需兼顾突发与平滑的场景(如秒杀) |
分布式限流 |
高 |
高 |
支持 |
高 |
分布式系统全局限流(如电商大促) |
三、实际应用中的选型策略
- 单机场景
-
- 优先选择令牌桶算法(如Guava RateLimiter),兼顾突发流量与平滑性。
- 若需简单实现,可使用滑动窗口计数器。
- 分布式场景
-
- 使用Redis + Lua脚本实现分布式令牌桶或滑动窗口,保证原子性操作。
- 复杂场景可选用Sentinel或Resilience4j等框架,内置多种限流策略。
- 特殊需求
-
- 严格恒定速率:漏桶算法(如网络流量整形)。
- 冷启动保护:令牌桶的预热模式(SmoothWarmingUp)。
四、总结
限流算法的核心目标是平衡系统负载与用户体验。选择时需结合业务场景特点:
- 高并发+突发流量:令牌桶算法。
- 严格速率控制:漏桶算法。
- 分布式全局限流:Redis + Lua或Sentinel。
实际应用中,可结合监控与动态调整(如自适应限流),进一步提升系统鲁棒性。