脚本宝典收集整理的这篇文章主要介绍了如何使用 Redis 来实现简单限流策略?,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
首先我们来看一个常见 的简单的限流策略。系统要限定用户的某个行为在指定的时间里只能允许发生 N 次,如何使用 Redis 的数据结构来实现这个限流的功能?
# 指定用户 user_id 的某个行为 action_key 在特定的时间内 period 只允许发生一定的次数 max_count def is_action_allowed(user_id, action_key, period, max_count): return True # 调用这个接口 , 一分钟内只允许最多回复 5 个帖子 can_reply = is_action_allowed("laoqian", "reply", 60, 5) if can_reply: do_reply() else: raise ActionThresholdOverflow()
这个限流需求中存在一个滑动时间窗口,想想 zset 数据结构的 score 值,是不是可以通过 score 来圈出这个时间窗口来。而且我们只需要保留这个时间窗口,窗口之外的数据都可以砍掉。那这个 zset 的 value 填什么比较合适呢?它只需要保证唯一性即可,用 uuid 会比较浪费空间,那就改用毫秒时间戳吧。
如图所示,用一个 zset 结构记录用户的行为历史,每一个行为都会作为 zset 中的一个 key 保存下来。同一个用户同一种行为用一个 zset 记录。
为节省内存,我们只需要保留时间窗口内的行为记录,同时如果用户是冷用户,滑动时间窗口内的行为是空记录,那么这个 zset 就可以从内存中移除,不再占用空间。
通过统计滑动窗口内的行为数量与阈值 max_count 进行比较就可以得出当前的行为是否允许。用代码表示如下:
# coding: utf8 import time import redis client = redis.StrictRedis() def is_action_allowed(user_id, action_key, period, max_count): key = 'hist:%s:%s' % (user_id, action_key) now_ts = int(time.time() * 1000) # 毫秒时间戳 with client.pipeline() as pipe: # client 是 StrictRedis 实例 # 记录行为 pipe.zadd(key, now_ts, now_ts) # value 和 score 都使用毫秒时间戳 # 移除时间窗口之前的行为记录,剩下的都是时间窗口内的 pipe.zremrangebyscore(key, 0, now_ts - period * 1000) # 获取窗口内的行为数量 pipe.zcard(key) # 设置 zset 过期时间,避免冷用户持续占用内存 # 过期时间应该等于时间窗口的长度,再多宽限 1s pipe.expire(key, period + 1) # 批量执行 _, _, current_count, _ = pipe.execute() # 比较数量是否超标 return current_count <= max_count for i in range(20): print is_action_allowed("laoqian", "reply", 60, 5)
以上是脚本宝典为你收集整理的如何使用 Redis 来实现简单限流策略?全部内容,希望文章能够帮你解决如何使用 Redis 来实现简单限流策略?所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。