redis限流方法
1. 利用之前的redis锁来处理队列请求
利用set nx 原子操作强行排队
2. 使用zset有序集合限定某一时间内的流量
原理
zset为有序集合, 记录下某一key值,相同分数, 不同访问时间
zadd user:10 0 1617070146897, 请求到来时, 获取到(限流总数-1)的有序数据量, 即当前限制key的次数访问记录, 判断第一个值的时间, 是否为在限制区间内
相关命令操作
记限制单个用户发送验证码的访问频率为1分钟1次, 5分钟2次,1小时5次, 一天10次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 # 请求进入, 获取已存入的
zcard user:10:$url => $count
# 获取前一条数据(每分钟)
zrange user:10:$url -1 -1
# 对比时间 $time -$result < 1000
# 获取前一条数据(5分钟)
zrange user:10:$url -2 -2
# 对比时间 $time -$result < 5000
# 获取前一条数据(60分钟)
zrange user:10:$url -5 -5
# 对比时间 $time -$result < 3600000
# 获取前一条数据(一天)
zrange user:10:$url -10 -10
# 对比时间 $time -$result < 24 * 3600 * 000
# 全部通过, 记下本次
zadd user:10:$url $time $time
# 同时删除,超过24小时+1ms的数据
zremrangebyscore user:10:$url 0 ($time - 24 * 3600 * 1000 + 1)
# 可以先查询再删除,减少数据变动
zcount user:10:$url 0 ($time - 24 * 3600 * 1000 + 1)
# 注意点: 每条数据的最大保存时间为,限制幅度的最大时间, 此处为 24 * 3600 + 1
相关代码:
1 | class RateLimiter { |
3. 使用令牌桶算法限流
- 漏桶
以一定速度生成令牌, 放入桶内, 请求来临时, 桶内以固定速率释放令牌, 请求获取到令牌,则继续进行, 无峰值访问, 实际请求强制排队等候, 类似setnx, 可以用
lpush/blpop模拟实现, 假定生成与释放令牌速度相同, 即定时生成即消费
漏桶
1 | # 生成 |
- 令牌桶
以一定速度生成令牌, 放入桶内, 请求来临时,从桶内获取令牌, 如果桶内为空则拒绝请求, 当请求速度大于令牌生成速度时, 桶内在一定时间内为空, 产生拒绝服务, 可以产生较小峰值
共同缺点, 需要额外进程/线程以固定速率生成令牌放入队列, 利用的是 lpush/blpop/llen适合通用接口流量削峰填谷
令牌桶
1 | # 额外进程生成令牌 |
本文作者 : 萧逸雨
原文链接 : http://qiubo.ink/2021/03/04/redis限流方法/
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!