redis限流怎么做

限流 Rate Limiting:控制单位时间内处理请求的频率或数量,从而保护系统免受过载请求的冲击。

目的主要有:

   1. 防止恶意攻击

   2. 避免服务雪崩 当上游系统出现突发流量,或者下游服务响应变慢时,通过限流保证系统正常运行不挂掉。

方法一 固定窗口限流 Fixed Window

设定时间窗口,比如 1分钟 ,创建一个过期时间60秒的key,内容放一个数字。

每访问一次 先判断数字有没有超限(没有则新建设为0),比如100 。如果没超限,则执行incr操作将数字加1。

超限了则打回。

优点:实现简单,内存占用少,只需要一个key,值也只是一个数字。

缺点:可能存在临界问题。比如,每分钟限制100个请求,最后一秒来了99或者100个请求,重置窗口后又来了100个请求,那么窗口切换的瞬间系统就要承受限制数两倍的请求。可能导致系统压力大。


方法二 滑动窗口限流 Sliding Window

设置一个有序集合 zset ,set成员的分数和值都是请求时间戳。

每次请求时,先使用 zremrangebyscore 窗口key  当前时间戳减去窗口时间如60秒

使用zcard获取剩余的数量,即当前窗口内有多少请求数。如果小于阈值,则使用zadd加入当前时间戳。否则拒绝请求。

是否给zset设置过期时间,根据需要来。


方法三 令牌桶算法 Token Bucket

设定一个固定容量的“桶”,以恒定速率向桶中添加令牌(token),每个请求需要先从桶中获取一个令牌,有令牌才能处理请求,否则拒绝或等待。

实现方式:

使用一个有序集合(zset)或 Redis 的 INCR/EXPIRE 配合时间戳记录,维护当前令牌数量和上次填充时间。

也可以用 Redis 脚本(Lua)实现原子操作。

例如:

  • 桶容量为 100 个令牌
  • 每秒新增 10 个令牌
  • 每次请求尝试获取 1 个令牌
  • 若当前令牌数 > 0,则减少 1 并放行;否则拒绝请求

优点

  1. 允许一定程度的突发流量:只要桶中有令牌,就可以快速处理一批请求,适合应对短时高峰。
  2. 平滑控制平均速率,同时具备灵活性。
  3. 实现相对直观,可结合 Redis 高效完成。

缺点

  1. 实现比固定窗口复杂,需要维护令牌生成逻辑。
  2. 使用 Lua 脚本时需注意性能和原子性边界。
  3. 若未合理设置桶容量,仍可能造成瞬时压力。


方法四 漏桶算法 Leak Bucket

请求像水一样“流入”一个固定容量的“漏桶”,桶底以恒定速率“漏水”(即处理请求)。如果流入速度超过漏水速度,桶满后新的请求将被丢弃或排队

与令牌桶不同:

  • 漏桶强调请求处理速率恒定,无论流入多快,流出始终平稳。
  • 即使系统空闲,也不会“积攒”处理能力。

实现方式:

使用 Redis 记录上一次请求处理的时间和当前“水位”(即待处理请求数),通过时间差计算可“漏出”的请求数。

例如:

  • 漏水速率为每秒 10 个请求
  • 桶容量为 50
  • 每次请求来时,计算从上次到现在能漏掉多少请求,更新当前水位
  • 若加水后不超过容量,则允许;否则拒绝

优点

  1. 输出速率绝对平滑,能有效削峰填谷,防止系统被突发流量冲击。
  2. 可严格控制最大并发,保护后端服务稳定性。
  3. 适合对响应延迟敏感、要求稳定吞吐的场景。

缺点

  1. 无法应对突发流量:即使系统有能力处理,也必须按固定速率“漏水”,可能导致资源利用率低。
  2. 实现略复杂,需精确计算时间间隔和水位。
  3. 在低负载时不能充分利用系统能力。