Redis 应用02 简单限流/限制用户单位时间内的行为次数
程序员文章站
2022-07-05 10:59:30
...
简单限流
回复帖子、点赞等操作,经常会提示你操作太快,也就是一个简单的限流问题。
如一分钟用户最多回复5条,超过就会进行限制,用redis如何设计?
实现思路
使用zset
数据结构, 每个用户的行为作为redis中的key
比如 limit:tom:reply
, 表示限制tom回复
存储的数据为 value:sorce
,
value
可以使用时间戳 或者uuid唯一值
sorce
使用发生行为的时间
# 01
# 每次操作行为,添加 value:sorce 使用zadd
# 02
# 删除1分钟之前的操作行为,1分钟是我自己设的,可以使用 zremrangebyscore
# zremrangebyscore(key, 0, now_ts - 60 * 1000)
# 03
# 计算zset中数据的个数,就是1分钟内的行为次数
# 04
# 我们限制为N,zset查询的数量为count,比较N和count的大小
代码
# coding: utf8
import uuid
import time
import redis
client = redis.StrictRedis(host='192.168.56.111', port=6379, db=0)
def is_action_allowed(user_id, action_key, period, max_count):
key = 'limit:%s:%s' % (user_id, action_key)
now_ts = int(time.time() * 1000) # 毫秒时间戳
with client.pipeline() as pipe: # client 是 StrictRedis 实例
# 操作1
# 想zset中添加数据 zadd redis.py版本3和2有差异
# zset中value采用uuid,使用时间戳也可以,但是高并发限制次数不准确,但也完全可以接受,看需求。
# zset中sorce采用时间戳
pipe.zadd(key, {str(uuid.uuid4()):now_ts} ) # value 和 score 都使用毫秒时间戳
# 操作2
# 删除60秒(period)之前的数据
pipe.zremrangebyscore(key, 0, now_ts - period * 1000)
# 操作3
# 获取zset中数量
pipe.zcard(key)
# 设置 zset 过期时间,避免冷用户持续占用内存
# 过期时间应该等于时间窗口的长度,再多宽限 1s
pipe.expire(key, period + 1)
# 批量执行,取操作3的值,pipe.execute() 返回结果列表
_, _, current_count, _ = pipe.execute()
# 比较数量是否超标,返回True/False
return current_count <= max_count
for i in range(20):
print(i,is_action_allowed("laoqian", "reply", 60, 5))
上一篇: Retrofit 原理简析
下一篇: 利用Redis实现单位时间内请求次数限制