Redis 限流

Redis 可以用来做限流,常见的限流实现方式包括以下几种:

1. 固定窗口计数限流

适用于简单的请求限流,比如每秒最多允许 100 次请求。

实现方式:

  • 设定一个键(Key),比如 rate_limit:user_123
  • 在固定时间窗口(如 1 秒)内累加请求计数
  • 若计数超过阈值,则拒绝请求

示例代码(使用 Lua 脚本实现原子操作):

local key = KEYS[1]         -- 限流的 Redis 键
local limit = tonumber(ARGV[1])  -- 最大请求数
local expire_time = tonumber(ARGV[2]) -- 窗口过期时间 (秒)

local current = redis.call("INCR", key)
if current == 1 then
    redis.call("EXPIRE", key, expire_time)
end

if current > limit then
    return 0  -- 限流
else
    return 1  -- 允许请求
end

使用示例(在 Java 中执行):

String script = "..." // 上面的 Lua 脚本
List<String> keys = Collections.singletonList("rate_limit:user_123");
List<String> args = Arrays.asList("100", "1"); // 100 次/秒
Long result = (Long) jedis.eval(script, keys, args);
if (result == 0) {
    System.out.println("请求过多,限流!");
}

2. 滑动窗口限流

固定窗口的缺点是,窗口切换时可能导致流量突增。滑动窗口限流可以缓解这个问题。

实现方式:

  • 维护一个 有序集合(Sorted Set),记录请求时间戳
  • 每次请求时,移除超出时间范围的数据
  • 判断当前窗口内的请求数是否超过阈值

示例代码:

local key = KEYS[1]
local now = tonumber(ARGV[1])
local window_size = tonumber(ARGV[2])
local max_count = tonumber(ARGV[3])

redis.call("ZREMRANGEBYSCORE", key, 0, now - window_size)
local count = redis.call("ZCARD", key)

if count >= max_count then
    return 0
else
    redis.call("ZADD", key, now, now)
    redis.call("EXPIRE", key, window_size)
    return 1
end

3. 令牌桶算法

令牌桶适用于 平滑流量,允许一定程度的突发流量。

实现方式:

  • 设定一个令牌桶,每秒按固定速率生成令牌
  • 请求时从桶里取令牌,若令牌不足则拒绝请求

Redis 实现(Lua 脚本):

local key = KEYS[1]
local rate = tonumber(ARGV[1]) -- 令牌生成速率(每秒生成多少)
local capacity = tonumber(ARGV[2]) -- 桶容量
local now = tonumber(ARGV[3])

local token_key = key .. ":tokens"
local timestamp_key = key .. ":timestamp"

local last_time = tonumber(redis.call("GET", timestamp_key)) or now
local tokens = tonumber(redis.call("GET", token_key)) or capacity

local elapsed = now - last_time
local new_tokens = math.min(capacity, tokens + (elapsed * rate))
if new_tokens < 1 then
    return 0  -- 没有令牌,拒绝请求
else
    redis.call("SET", token_key, new_tokens - 1)
    redis.call("SET", timestamp_key, now)
    return 1  -- 允许请求
end

4. 漏桶算法

漏桶算法适用于 平滑处理请求,防止流量突增。

实现方式:

  • 设定一个队列(List),存放请求
  • 以固定速率处理请求,多余的请求直接丢弃

示例:

local key = KEYS[1]
local rate = tonumber(ARGV[1])  -- 处理速率(多少秒处理一个请求)
local capacity = tonumber(ARGV[2]) -- 队列最大长度
local now = tonumber(ARGV[3])

local size = redis.call("LLEN", key)
if size >= capacity then
    return 0 -- 队列已满,丢弃请求
else
    redis.call("LPUSH", key, now)
    redis.call("LTRIM", key, 0, capacity - 1)
    redis.call("EXPIRE", key, rate * capacity)
    return 1
end

选择适合的限流算法

算法适用场景特点
固定窗口简单限流,适合低并发实现简单,窗口切换时可能突发
滑动窗口适用于高并发场景计算较复杂,能更平滑地限流
令牌桶允许突发流量,保证一定吞吐量适用于 API 请求限流
漏桶平滑请求处理,防止流量抖动控制流出速率,避免流量过载

你目前的项目是 高并发的 Spring Boot 订单系统,可以考虑 令牌桶算法,用 Redis 来实现限流,结合 Spring Boot 的拦截器或者网关过滤器来执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值