接口限流自动装配(支持多种限流策略和算法)

三大主流限流算法简介

这三种算法是分布式系统中实现限流的基石。它们都借助 Redis 的高性能内存读写和 Lua 脚本的原子性操作,来确保在多台服务器(集群)环境下限流策略的准确性和一致性。

1. 令牌桶算法 (Token Bucket)

这是目前应用最广泛的算法,因为它在限制平均速率的同时,允许一定程度的突发流量。

  • 核心思想 (比喻)
    想象一个会自动出票的机器(桶),它以固定的速度(比如每秒2张)出票,但最多只能存放10张票(容量)。每个请求过来,都必须从机器里拿走一张票才能通过。

    • 匀速出票:系统按固定速率生成令牌。
    • 允许突发:如果短时间内没有请求,票会积攒起来。当突然来了一批请求时,它们可以快速消耗掉所有积攒的票,从而被立即处理。
    • 速率限制:一旦积攒的票用完,请求的处理速度就只能等于票的生成速度。
  • Redis 实现方式

    • 数据结构: HASH
    • 字段:
      • tokens: 当前剩余的令牌数。
      • last_ts: 上次刷新令牌的时间戳。
    • Lua 脚本逻辑:
      1. 根据当前时间与last_ts的时间差,计算应补充多少新令牌。
      2. 将新令牌加入桶中(不能超过容量)。
      3. 判断当前令牌数是否足够本次请求消耗(通常是1)。
      4. 如果足够,则扣减令牌,更新last_ts,返回成功。否则返回失败。
  • 特点与适用场景

    • 特点: 灵活,既能限制平均速率,又能应对突发流量。
    • 场景: 通用的 API 接口限流、网关限流、电商秒杀等,适用于大部分需要限流的Web服务。

2. 漏桶算法 (Leaky Bucket)

漏桶算法的核心是强制平滑流出速率,非常适合保护下游系统。

  • 核心思想 (比喻)
    想象一个底部有洞的木桶。水(请求)可以随时、快速地倒入桶中,但水只能以固定的速度从洞口漏出(被处理)。

    • 请求积压:请求到来时,如果桶里还有空间,就先存放在桶里。
    • 匀速处理:系统以恒定的速率从桶里取出请求来处理,不管桶里积压了多少。
    • 拒绝请求:如果水倒得太快,桶满了,多余的水就会溢出(请求被直接拒绝)。
  • Redis 实现方式

    • 数据结构: HASH
    • 字段:
      • level: 桶的当前水位(积压的请求数)。
      • last_ts: 上次漏水的时间戳。
    • Lua 脚本逻辑:
      1. 根据当前时间与last_ts的时间差和漏出速率,计算漏掉了多少水(处理了多少请求)。
      2. 更新当前水位。
      3. 判断加入新请求后,水位是否会超过桶的容量。
      4. 如果不会溢出,则增加水位,更新last_ts,返回成功。否则返回失败。
  • 特点与适用场景

    • 特点: 强制平滑处理速率,有效地保护后端服务。
    • 场景: 短信发送、邮件推送、调用第三方有严格频率限制的API等,确保不会因突发流量冲垮下游系统。

3. 滑动窗口算法 (Sliding Window)

这是一种非常精确的限流算法,完美解决了简单计数器在窗口边界的统计不准问题。

  • 核心思想 (比喻)
    想象你在看一列匀速行驶的火车,你的眼睛只能透过一个固定长度的“窗口”去看。你关心的是,在任何时刻,你窗口里能看到的火车车厢(请求)有几节。

    • 动态窗口:这个窗口随着时间的推移不断向前“滑动”。
    • 精确计数:只统计当前时间窗口内的请求总数。
    • 清理过期记录:随着窗口滑动,旧的、已经滑出窗口的请求记录会被自动清除。
  • Redis 实现方式

    • 数据结构: ZSET (有序集合)。
    • 存储内容:
      • Score: 请求的毫秒级时间戳。
      • Member: 唯一的请求ID(通常是时间戳-UUID),以防重复。
    • Lua 脚本逻辑:
      1. 使用 ZREMRANGEBYSCORE 命令,原子性地移除所有时间戳早于“当前时间 - 窗口大小”的旧记录。
      2. 使用 ZCARD 命令,获取当前窗口内还剩下多少记录。
      3. 判断该数量是否小于限流阈值。
      4. 如果小于,则用 ZADD 将当前请求加入ZSET,返回成功。否则返回失败。
  • 特点与适用场景

    • 特点: 限流控制非常精确,平滑度高。
    • 场景: 对限流精度要求极高的场景,如金融交易、防爬虫、防止密码暴力破解等。

总结对比

算法 核心比喻 关键特点 Redis 数据结构 典型场景
令牌桶 存票消费 允许突发流量 HASH 通用API限流、秒杀
漏桶 匀速漏水 强制平滑速率 HASH 保护下游服务、推送
滑动窗口 移动时间窗 精确控制 ZSET 金融、防刷、防爆破

源码实现

源码地址

使用

  • 引入依赖
1
2
3
4
5
<dependency>
<groupId>rate-limiter</groupId>
<artifactId>rate-limiter-spring-boot-autoconfigure</artifactId>
<version>1.0</version>
</dependency>
  • 环境配置
1
2
3
4
5
6
7
8
9
10
11
12
spring:
data:
redis:
host: localhost
port: 6379
password: 123

rate-limiter:
enabled: true
# 将默认算法切换为Redis的实现
default-algorithm: redisTokenBucket
default-key-resolver: ipKeyResolver
  • 使用