欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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))
相关标签: Redis