Skip to content

限流底层原理是什么

限流的底层原理是通过限制请求或流量的速率,保护系统免受过载影响。其核心是基于算法(如令牌桶、漏桶、计数器)和数据结构(如队列、计数器),在指定时间窗口内控制访问频率,确保系统稳定运行。


1. 限流概述

作用

  • 防止系统因流量过大崩溃(如 DDoS 攻击)。
  • 保障服务质量(如 QPS 超限降级)。

应用场景

  • API 接口限流(如每秒 100 次请求)。
  • 数据库连接限制。
  • 消息队列消费速率控制。

2. 限流底层原理

核心思想

  • 流量控制:在时间窗口内限制请求数或速率。
  • 拒绝策略:超出限制的请求被拒绝、排队或降级。

常见算法

(1) 计数器法(Fixed Window)
  • 原理
  • 在固定时间窗口(如 1 秒)内,使用计数器记录请求数。
  • 若超出阈值(如 100),拒绝后续请求。
  • 窗口结束,重置计数器。
  • 实现
  • 用原子计数器(如 AtomicInteger)或 Redis INCR
  • 示例
  • 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 计数。
  • 队列:滑动窗口用时间队列,漏桶用请求队列。
  • 时间戳:记录窗口或令牌生成时间。

并发控制

  • :如 synchronizedReentrantLock
  • 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:集成限流。
  • 优化
  • 预分配:提前生成令牌。
  • 降级:超限时返回默认结果。
  • 面试点
  • 问“原理”时,提令牌桶流程。
  • 问“对比”时,提突发流量支持。

总结

限流底层通过计数器、滑动窗口、令牌桶或漏桶算法控制流量,依赖原子操作或锁保证并发安全。面试时,可写令牌桶代码或提分布式实现,展示理解深度。