限流底层原理是什么
限流的底层原理是通过限制请求或流量的速率,保护系统免受过载影响。其核心是基于算法(如令牌桶、漏桶、计数器)和数据结构(如队列、计数器),在指定时间窗口内控制访问频率,确保系统稳定运行。
1. 限流概述
作用
- 防止系统因流量过大崩溃(如 DDoS 攻击)。
- 保障服务质量(如 QPS 超限降级)。
应用场景
- API 接口限流(如每秒 100 次请求)。
- 数据库连接限制。
- 消息队列消费速率控制。
2. 限流底层原理
核心思想
- 流量控制:在时间窗口内限制请求数或速率。
- 拒绝策略:超出限制的请求被拒绝、排队或降级。
常见算法
(1) 计数器法(Fixed Window)
- 原理:
- 在固定时间窗口(如 1 秒)内,使用计数器记录请求数。
- 若超出阈值(如 100),拒绝后续请求。
- 窗口结束,重置计数器。
- 实现:
- 用原子计数器(如
AtomicInteger
)或 RedisINCR
。 - 示例:
- 1 秒限 100 次,第 101 次拒绝。
- 缺点:
- 边界问题:窗口切换瞬间可能突刺(如 0:59 和 1:00 各 100 次)。
(2) 滑动窗口(Sliding Window)
- 原理:
- 将时间分成小块(如 1 秒分 10 个 100ms),记录每块请求数。
- 滑动计算最近窗口(如 1 秒)的总数,判断是否超限。
- 实现:
- 用队列或环形数组存时间片计数。
- 示例:
- 最近 1 秒总和 ≤ 100。
- 优点:
- 平滑流量,无边界突刺。
(3) 令牌桶(Token Bucket)
- 原理:
- 按固定速率生成令牌,存入桶中(容量有限)。
- 请求到来时尝试获取令牌,成功则通过,失败则拒绝。
- 实现:
- 维护令牌数(如
AtomicLong
),定时补充。 - 示例:
- 每秒放 100 个令牌,请求超过 100 拒绝。
- 优点:
- 支持突发流量(桶内有令牌即可)。
(4) 漏桶(Leaky Bucket)
- 原理:
- 请求进入固定容量桶,按恒定速率流出。
- 桶满时,新请求被拒绝。
- 实现:
- 用队列模拟桶,定时处理。
- 示例:
- 桶容量 100,每秒漏 10 个,超 100 拒绝。
- 优点:
- 平滑输出速率。
3. 底层实现细节
数据结构
- 计数器:
AtomicInteger
或 Redis 计数。 - 队列:滑动窗口用时间队列,漏桶用请求队列。
- 时间戳:记录窗口或令牌生成时间。
并发控制
- 锁:如
synchronized
或ReentrantLock
。 - CAS:无锁操作(如
AtomicLong.compareAndSet
)。 - 分布式:Redis、ZooKeeper 实现集群限流。
示例(令牌桶 Java)
public class TokenBucket {
private final long capacity; // 桶容量
private final long rate; // 令牌生成速率(每秒)
private long tokens; // 当前令牌数
private long lastRefill; // 上次补充时间
public TokenBucket(long capacity, long rate) {
this.capacity = capacity;
this.rate = rate;
this.tokens = capacity;
this.lastRefill = System.currentTimeMillis();
}
private synchronized void refill() {
long now = System.currentTimeMillis();
long elapsed = now - lastRefill;
long newTokens = elapsed * rate / 1000;
tokens = Math.min(capacity, tokens + newTokens);
lastRefill = now;
}
public synchronized boolean tryAcquire() {
refill();
if (tokens > 0) {
tokens--;
return true;
}
return false;
}
}
// 使用
TokenBucket bucket = new TokenBucket(100, 10); // 容量 100,每秒 10 个
if (bucket.tryAcquire()) {
// 处理请求
} else {
// 拒绝
}
4. 算法对比
算法 | 优点 | 缺点 |
---|---|---|
计数器 | 简单易实现 | 边界突刺 |
滑动窗口 | 平滑流量 | 实现复杂,内存占用 |
令牌桶 | 支持突发流量 | 配置需调优 |
漏桶 | 输出平滑 | 不支持突发流量 |
5. 延伸与面试角度
- 分布式限流:
- Redis:
INCR
+ 过期时间。 - Sentinel:集群限流框架。
- 实际应用:
- Nginx:
limit_req
模块(漏桶)。 - Spring Cloud Gateway:集成限流。
- 优化:
- 预分配:提前生成令牌。
- 降级:超限时返回默认结果。
- 面试点:
- 问“原理”时,提令牌桶流程。
- 问“对比”时,提突发流量支持。
总结
限流底层通过计数器、滑动窗口、令牌桶或漏桶算法控制流量,依赖原子操作或锁保证并发安全。面试时,可写令牌桶代码或提分布式实现,展示理解深度。