用Redis来做漏桶算法限流,感觉挺实用也不复杂的实现方法分享
- 问答
- 2026-01-02 06:23:06
- 1
最近在琢磨接口限流的事儿,看到有朋友分享了一个用Redis来实现漏桶算法的方法,感觉思路挺清晰,实践起来也不复杂,这里就把这个法子捋一捋,这个方法的精髓在于利用了Redis的几个基本命令,把漏桶模型给模拟出来了。
核心思想:漏桶是怎么用Redis表示的?
想象一下,漏桶就是一个固定容量的桶,上面有个口子进水(请求进来),下面有个小孔以固定速率漏水(处理请求),在Redis里,我们可以用一个普通的键值对来代表这个桶,这个键(Key)可以叫成类似 rate_limit:user123 或者 rate_limit:192.168.1.1 这样的,用来区分不同的限流对象。
这个键对应的值(Value)是什么呢?它存的是这个桶里当前的水量,也就是当前积压的请求数量,这个水量一开始是0。
关键操作:如何判断一个请求该不该被放行?
整个流程可以拆解成几个步骤,为了保证在执行这些步骤时不会被其他请求打扰,我们需要用Redis的Lua脚本来实现原子性操作,确保判断和操作是“一气呵成”的。
Lua脚本里大概会做下面这几件事:
-
获取当前桶的状态: 脚本会去Redis里查一下这个限流键对应的当前水量是多少,如果这个键不存在(比如第一次请求),那就说明桶是空的,水量为0。

-
计算漏掉的水量: 漏桶不是一直在漏水嘛?所以我们需要算出从上一次漏水到现在,这段时间里又漏掉了多少水,这里就需要一个参数:漏水速率,我们设定系统每秒只能处理10个请求,那么漏水速率就是每100毫秒漏掉1个请求。 我们还需要记录上一次漏水的时间戳,这个时间戳也可以存在Redis里,用另一个键来保存,
rate_limit:user123:last_time,脚本里会取出这个时间戳,然后用当前时间减去它,再乘以漏水速率,就能算出这段时间应该漏掉的水量了。 -
更新当前水量: 算出了漏水量之后,我们就能更新桶里的当前水量了,新的水量 = 老的水量 - 漏水量,水量最少不能少于0,所以如果算出来是负数,就把它设为0。
-
判断是否加水(是否允许请求): 现在要看新的请求(可以想象成一杯水)能不能倒进桶里了,这取决于桶满没满,桶的容量是另一个关键参数:桶的大小。
- 更新后的当前水量 + 1(这一杯水) 小于等于 桶的大小,说明桶还没满,这个请求可以被允许,我们就执行加水操作:把当前水量加1,同时更新一下“上一次漏水的时间戳”为当前时间,然后脚本返回一个信号,比如返回
1,表示请求通过。 - 反之,如果加水后超过了桶的容量,说明桶已经满了,这个请求就会被拒绝(被限流),我们不改变当前水量和上次时间戳,脚本返回
0,表示请求被拒绝。
- 更新后的当前水量 + 1(这一杯水) 小于等于 桶的大小,说明桶还没满,这个请求可以被允许,我们就执行加水操作:把当前水量加1,同时更新一下“上一次漏水的时间戳”为当前时间,然后脚本返回一个信号,比如返回
举个例子来走一遍流程

假设我们设置桶容量是5,漏水速率是每秒1个(即每1000毫秒漏1个)。
- 第1秒: 一下子来了3个请求。
- 第一个请求进来:当前水量0,允许通过,水量变为1。
- 第二个请求进来:当前水量1,允许通过,水量变为2。
- 第三个请求进来:当前水量2,允许通过,水量变为3。
- 第2秒: 又来了4个请求,这时候,距离上次操作已经过去了1秒,应该漏掉1个单位的水。
- 先计算:当前水量3 - 漏掉的水量1 = 更新水量2。
- 第一个请求:2+1=3 < 5,允许,水量变3。
- 第二个请求:3+1=4 < 5,允许,水量变4。
- 第三个请求:4+1=5 = 5,允许(通常等于容量也算允许),水量变5。
- 第四个请求:5+1=6 > 5,拒绝!请求被限流。
- 第3秒: 来了1个请求,距离上次操作又过去了1秒,漏掉1单位水。
- 先计算:当前水量5 - 漏掉的水量1 = 更新水量4。
- 这个请求:4+1=5 <= 5,允许通过,水量变5。
你看,通过这样的模拟,请求的速率即使有波动(比如第1秒来3个,第2秒来4个),但最终流出(被处理)的速率是平稳的(每秒1个),多余的请求会被暂时拦住,这就达到了限流的目的。
这个方法的好处和需要注意的地方
好处很明显:
- 简单直接: 不需要引入额外的中间件,只用Redis的基本功能。
- 性能不错: Redis本身很快,加上Lua脚本的原子性,能应对较高的并发判断。
- 理解直观: 漏桶算法本身模型简单,容易理解和调整参数。
也有些地方要注意:
- Redis稳定性: 限流功能强依赖Redis,如果Redis挂了,限流就失效了,所以Redis本身要做高可用。
- 时间同步: 这个算法依赖于系统时间来计算时间差,要确保应用服务器和Redis服务器的时间基本同步。
- 内存占用: 如果限流的Key非常多(比如按每个用户ID限流,用户量巨大),会占用不少Redis内存,可以考虑给这些Key设置一个过期时间,比如长时间不活动的用户对应的限流Key可以自动清除,需要时再重新创建。
- 非精确平滑: 这毕竟是一个模拟的漏桶,不是真正的连续漏水,它的平滑程度取决于请求到来的间隔和我们对“上一次漏水时间”更新的频率,但在大多数场景下,这种精度已经足够了。
这是一个非常实用且易于落地的限流方案,对于API网关、防止爬虫、秒杀场景等需要控制请求速率的场合,能起到不错的效果。
本文由凤伟才于2026-01-02发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/72916.html
