限流相关知识的学习(入门版)

刚刚接触学习限流这个概念知识, 经过一段时间的学习实践, 分享一下自己的心得

一、什么是限流?

1.1 限流的定义

限流(Rate Limiting) 是一种控制系统接收请求速率的技术。就像高速公路的收费站控制车辆进入速度一样,限流控制服务器处理请求的速度,防止服务器被过多请求压垮。

1.2 为什么需要限流?

想象一个场景:

  • 你的网站正常情况下每秒处理 100 个请求
  • 突然有人用脚本每秒发送 10000 个请求
  • 服务器资源被耗尽,正常用户也无法访问

限流的作用:

  1. 保护服务器 - 防止资源耗尽(CPU、内存、数据库连接等)
  2. 保证服务质量 - 确保正常用户的请求能被处理(避免大量请求访问导致服务器崩溃)
  3. 防止恶意攻击 - 阻止 DDoS 攻击、暴力破解等,保护服务器
  4. 控制成本 - 避免因突发流量产生高额费用

1.3 生活中的限流例子

场景 限流方式 说明
游乐场 排队 + 限流 控制同时游玩人数
医院挂号 每日限额 每天只挂 500 个号
抢购活动 排队系统 防止服务器崩溃
API 接口 QPS 限制 控制每秒请求数

二、专有名词与限流算法解释

2.1 QPS(Queries Per Second)

QPS = 每秒查询数,表示服务器每秒能处理的请求数量。

复制代码
示例:
如果 QPS 限制为 10,意味着:
- 每秒最多处理 10 个请求
- 第 11 个请求会被拒绝(限流)

时间轴:
第1秒: [请求1] [请求2] [请求3] ... [请求10] → 全部处理
第1秒: [请求1] [请求2] ... [请求10] [请求11] → 请求11被拒绝

相关概念:

  • TPS(Transactions Per Second):每秒事务数,通常指数据库操作
  • RPS(Requests Per Second):每秒请求数,和 QPS 类似
  • 吞吐量(Throughput):单位时间内处理的请求数量

2.2 固定窗口(Fixed Window)

固定窗口 是一种限流算法,将时间划分为固定的窗口(如 1 秒),在每个窗口内计数请求数。

复制代码
时间被划分为固定的 1 秒窗口:

|<---- 窗口1 (0-1秒) ---->|<---- 窗口2 (1-2秒) ---->|<---- 窗口3 (2-3秒) ---->|
|  请求: 1,2,3,4,5,6,7,8  |  请求: 1,2,3,4,5        |  请求: 1,2,3,4,5,6,7,8,9 |
|  计数: 8 (未超限)        |  计数: 5 (未超限)        |  计数: 9 (未超限)         |

限流阈值: 10 QPS

优点:

  • 实现简单
  • 性能好

缺点:

  • 窗口边界问题:如果在窗口结束前突然涌入大量请求,可能瞬间超过阈值

    窗口边界问题示例:

    |<---- 窗口1 ---->|<---- 窗口2 ---->|
    | 请求: 9个 | 请求: 9个 |
    | (最后0.1秒) | (最前0.1秒) |

    实际在 0.2 秒内处理了 18 个请求,远超 10 QPS 的限制!

2.3 滑动窗口(Sliding Window)

滑动窗口 是固定窗口的改进版,窗口随时间滑动,更平滑。

复制代码
滑动窗口示例(1秒窗口,每100ms滑动一次):

时间:    0ms   100ms  200ms  300ms  400ms  500ms
窗口:    [===]  [===]  [===]  [===]  [===]  [===]
         ↓      ↓      ↓      ↓      ↓      ↓
         滑动   滑动   滑动   滑动   滑动   滑动

每个时刻都统计过去 1 秒内的请求数

优点:

  • 更平滑,避免边界问题
  • 限流更精确

缺点:

  • 实现复杂
  • 内存消耗大(需要记录每个请求的时间戳)

2.4 漏桶算法(Leaky Bucket)

漏桶算法 就像一个漏桶,请求像水一样倒入桶中,以固定速率流出处理。

复制代码
漏桶算法示意图:

    请求进入
        ↓
    ┌───────┐
    │ █████ │  ← 桶(队列)
    │ █████ │
    │ █████ │
    └───┬───┘
        ↓
    固定速率流出(如每秒 10 个)
        ↓
    处理请求

工作原理:

  1. 请求进入桶(队列)
  2. 桶满则拒绝新请求
  3. 以固定速率从桶中取出请求处理

优点:

  • 严格限制处理速率
  • 平滑输出

缺点:

  • 无法应对突发流量
  • 即使服务器空闲,也只能按固定速率处理

2.5 令牌桶算法(Token Bucket)

令牌桶算法 以固定速率生成令牌,请求需要获取令牌才能被处理。

复制代码
令牌桶算法示意图:

    令牌生成器(每秒 10 个令牌)
        ↓
    ┌───────┐
    │ ○○○○○ │  ← 令牌桶(存放令牌)
    │ ○○○○○ │
    └───────┘
        ↓
    请求到达 → 获取令牌 → 处理请求
                  ↓
              没有令牌 → 拒绝请求

工作原理:

  1. 令牌以固定速率放入桶中
  2. 桶满则丢弃多余令牌
  3. 请求到达时,需要从桶中取一个令牌
  4. 有令牌则处理,没令牌则拒绝

优点:

  • 允许一定程度的突发流量(桶中有积累的令牌)
  • 实现相对简单

缺点:

  • 需要定时器生成令牌

2.6 Redis INCR 命令

Redis 是一个高性能的内存数据库,INCR 是 Redis 的原子自增命令。

bash 复制代码
# Redis INCR 命令示例
127.0.0.1:6379> SET counter 0
OK
127.0.0.1:6379> INCR counter
(integer) 1
127.0.0.1:6379> INCR counter
(integer) 2
127.0.0.1:6379> INCR counter
(integer) 3

原子性 意味着这个操作是不可分割的,多个请求同时执行 INCR 也不会出错。

在限流中的应用:

java 复制代码
// 伪代码
Long count = redis.incr("rate_limiter:ip:192.168.1.1");
if (count == 1) {
    redis.expire("rate_limiter:ip:192.168.1.1", 1); // 1秒后过期
}
if (count > 10) {
    return "限流"; // 超过 10 QPS
}

上述代码就是利用Redis实现了1秒只处理10个请求的逻辑

2.7 TTL(Time To Live)

TTL = 生存时间,表示数据在缓存中的存活时间。

复制代码
TTL 示例:

Key: rate_limiter:ip:192.168.1.1
Value: 5
TTL: 1 秒

1 秒后:
Key 自动删除(过期)
下次访问重新计数

2.8 过滤器(Filter)

过滤器 是 Web 应用中的一种组件,可以在请求到达控制器之前进行处理。

复制代码
请求处理流程:

客户端请求
    ↓
┌─────────────┐
│  过滤器1     │  ← 限流过滤器
├─────────────┤
│  过滤器2     │  ← 验证码过滤器
├─────────────┤
│  过滤器3     │  ← 认证过滤器
├─────────────┤
│  Controller  │  ← 业务逻辑
└─────────────┘
    ↓
响应返回客户端

2.9 Spring Security 过滤器链

Spring Security 是 Spring 框架的安全模块,使用过滤器链实现安全控制。

复制代码
Spring Security 过滤器链(简化版):

1. SecurityContextPersistenceFilter  ← 保存安全上下文
2. RateLimiterFilter                 ← 限流
3. CaptchaValidationFilter           ← 验证码验证
4. TokenAuthenticationFilter         ← Token 认证
5. ExceptionTranslationFilter        ← 异常处理
6. FilterSecurityInterceptor         ← 权限检查

2.10 分布式锁(Distributed Lock)

分布式锁 是在分布式系统中实现互斥访问的机制。

复制代码
分布式锁示例(使用 Redis SETNX):

请求A: SETNX lock:key value → 成功(获取锁)
请求B: SETNX lock:key value → 失败(锁已被占用)

请求A 处理完毕 → 删除锁
请求C: SETNX lock:key value → 成功(获取锁)

SETNX = SET if Not eXists,只有 key 不存在时才设置成功。


三、横向技术拓展

3.1 服务治理三剑客:限流、熔断、降级

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      服务治理三剑客                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐         │
│  │    限流      │    │    熔断      │    │    降级      │         │
│  │ Rate Limit  │    │  Circuit    │    │  Fallback   │         │
│  │             │    │  Breaker    │    │             │         │
│  └─────────────┘    └─────────────┘    └─────────────┘         │
│        ↓                  ↓                  ↓                  │
│  控制请求速率        快速失败           返回兜底响应              │
│  保护服务器          防止级联故障       保证核心功能              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
3.1.1 限流(Rate Limiting)

作用: 控制请求速率,防止服务器过载

复制代码
正常情况:
客户端 → [限流] → 服务器 → 响应

超过限制:
客户端 → [限流] → 拒绝请求 → 返回 429 Too Many Requests
3.1.2 熔断(Circuit Breaker)

作用: 当依赖服务出现故障时,快速失败,防止级联故障

复制代码
熔断器状态机:

    ┌─────────┐
    │  关闭    │ ← 正常状态,请求正常通过
    │ (Closed) │
    └────┬────┘
         │ 失败次数超过阈值
         ↓
    ┌─────────┐
    │  打开    │ ← 故障状态,请求直接失败
    │ (Open)   │
    └────┬────┘
         │ 超时后进入半开状态
         ↓
    ┌─────────┐
    │  半开    │ ← 尝试恢复,允许部分请求通过
    │ (Half-   │
    │  Open)   │
    └────┬────┘
         │ 请求成功 → 回到关闭状态
         │ 请求失败 → 回到打开状态

常用框架: Hystrix、Resilience4j、Sentinel

3.1.3 降级(Fallback)

作用: 当系统压力过大时,暂时关闭非核心功能,保证核心功能可用

复制代码
降级策略示例:

功能优先级:
1. 核心功能(必须保证):下单、支付
2. 重要功能(尽量保证):查询订单、查看商品
3. 非核心功能(可降级):推荐系统、评论系统

降级时:
- 核心功能:正常处理
- 重要功能:正常处理
- 非核心功能:返回默认值或缓存数据

3.2 API 网关限流

API 网关 是微服务架构中的统一入口,可以在网关层实现限流。

复制代码
微服务架构中的限流层次:

┌─────────────────────────────────────────────────────────────────┐
│                        客户端                                    │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  API 网关(如 Spring Cloud Gateway、Kong)                      │
│  ├─ 全局限流:保护整个系统                                       │
│  ├─ 路由限流:针对特定服务                                       │
│  └─ 用户限流:针对特定用户                                       │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  微服务 A    微服务 B    微服务 C    微服务 D                    │
│  (限流)      (限流)      (限流)      (限流)                      │
└─────────────────────────────────────────────────────────────────┘

常见 API 网关:

  • Spring Cloud Gateway:Spring 官方网关,支持限流
  • Kong:基于 Nginx 的高性能网关
  • Nginx:可通过 Lua 脚本实现限流
  • APISIX:Apache 开源的高性能网关

3.3 分布式限流

在分布式系统中,单机限流无法保证全局一致性,需要使用分布式限流。

复制代码
单机限流 vs 分布式限流:

单机限流:
┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│   服务器1    │  │   服务器2    │  │   服务器3    │
│  限流: 10 QPS│  │  限流: 10 QPS│  │  限流: 10 QPS│
└─────────────┘  └─────────────┘  └─────────────┘
                 总计: 30 QPS(不准确)

分布式限流:
┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│   服务器1    │  │   服务器2    │  │   服务器3    │
└──────┬──────┘  └──────┬──────┘  └──────┬──────┘
       │                │                │
       └────────────────┼────────────────┘
                        ↓
               ┌─────────────────┐
               │  Redis 集群     │
               │  全局限流: 10 QPS│
               └─────────────────┘

分布式限流实现方式:

  1. Redis + Lua 脚本(推荐)
lua 复制代码
-- Lua 脚本示例(原子操作)
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('GET', key) or "0")

if current + 1 > limit then
    return 0  -- 超限
else
    redis.call("INCR", key)
    if current == 0 then
        redis.call("EXPIRE", key, 1)
    end
    return 1  -- 未超限
end
  1. Redisson RateLimiter
java 复制代码
// 使用 Redisson 实现分布式限流
RRateLimiter rateLimiter = redisson.getRateLimiter("myRateLimiter");
rateLimiter.trySetRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);

if (rateLimiter.tryAcquire()) {
    // 处理请求
} else {
    // 拒绝请求
}
  1. Sentinel
java 复制代码
// 使用 Sentinel 实现限流
FlowRule rule = new FlowRule();
rule.setResource("myResource");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(10);
FlowRuleManager.loadRules(Collections.singletonList(rule));

3.4 限流算法对比

算法 实现复杂度 内存消耗 突发流量处理 精确度 适用场景
固定窗口 ⭐⭐ 简单限流
滑动窗口 ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ 精确限流
漏桶算法 ⭐⭐ ⭐⭐ ⭐⭐⭐ 流量整形
令牌桶算法 ⭐⭐ ⭐⭐ ⭐⭐⭐ 允许突发

3.5 常见限流框架对比

框架 语言 特点 适用场景
Sentinel Java 功能全面,阿里开源 微服务架构
Resilience4j Java 轻量级,函数式编程 Spring Boot
Guava RateLimiter Java 简单易用,单机限流 单体应用
Hystrix Java 已停止维护 遗留项目
Redis + Lua 任意 灵活,分布式支持 分布式系统