深入Redis(六)简单限流

简单限流

限流算法是一个在分布式领域经常被提起的话题,当系统处理能力有限时,如何阻止计划外的请求继续对系统施压,这是一个需要重视的问题。

除了控制流量,限流还有一个应用目的是用于控制用户行为,避免垃圾请求,比如严格限定在规定时间内某行为的允许次数。

如何使用Redis来实现简单限流策略?

系统要限定用户的某个行为在指定时间内只能允许发生N次,如何利用Redis的数据结构来实现这个限流的功能?

先定义这个接口

def is_action_allowed(user_id, action_key, period, max_count):
    return True

can_reply = is_action_allowed(‘tom‘, ‘reply‘, 60, 5)
if can_reply:
    do_reply()
else:
    raise ActionThresholdOverflow()

解决方案

利用zset数据结构的score值来作为时间窗口,value保证唯一性即可,用uuid比较浪费空间,用毫秒时间戳即可。

用一个zset结构记录用户的历史行为,每一个行为都会作为zset中的一个key保存下来,同一个用户的同一种行为用一个zset记录。

为节省内存,只保留时间窗口内的行为记录,如果用户是冷用户,窗口内的行为是空记录,则这个zset可以从内存中移除。

通过统计窗口内的行为数量与阈值进行比较就可以得出当前行为是否允许。

import time
import redis

pool = redis.ConnectionPool(host=‘localhost‘, port=6379)
client = redis.StrictRedis(connection_pool=pool)

def is_action_allowed(user_id, action_key, period, max_count):
    key = ‘hist:{}:{}‘.format(user_id, action_key)
    now_ts = int(time.time() * 1000)    # 毫秒时间戳
    with client.pipeline() as pipe:
        pipe.zadd(key, now_ts, now_ts)    # value和score都是毫秒时间戳
        pipe.zremrangebyscore(key, 0, now_ts - period * 1000)    # 移除时间窗口之前的行为记录
        pipe.zcard(key)    # 获取窗口内的行为数量
        pipe.expire(key, period + 1)    # 设置过期时间,避免冷用户持续占用内存,过期时间应等于窗口长度,这里多宽限1秒
        _, _, current_count, _ = pipe.execute()    # 批量执行
    return current_count <= max_count

for i in range(20):
    print(is_action_allowed(‘tom‘, ‘reply‘, 60, 5))

这几个连续的Redis操作都是针对同一个key的,因此可以用pipeline来显著提升Redis存取效率,但这个方案也有缺点,它要记录窗口内的所有记录,如果这个量特别大,就会消耗大量空间,因此是不适合简单限流的。

原文地址:https://www.cnblogs.com/ikct2017/p/9499440.html

时间: 2024-10-05 11:56:20

深入Redis(六)简单限流的相关文章

8.【Redis系列】Redis的高级应用-简单限流

原文:8.[Redis系列]Redis的高级应用-简单限流 限流在分布式系统中是一个经常被提到的话题,如果当前系统的能力,不足以承受那么大的访问量的时候,那么我们就要阻止外来请求对系统继续施压 实现简单限流 首先我们来看一个常见的简单限流策略,系统要限制每个用户在一定时间内的某个行为只能操作N次,如何是用redis的数据结构来实现这个限流的功能呢. 解决方案 这个限流需求中存在一个滑动时间窗口,想想 zset 数据结构的 score 值,是不是可以通过 score 来圈出这个时间窗口来.而且我们

redis之漏斗限流

Redis 4.0 提供了一个限流 Redis 模块,它叫 redis-cell.该模块也使用了漏斗算法,并提供了原子的限流指令.有了这个模块,限流问题就非常简单了. 原文地址:https://www.cnblogs.com/wuwuyong/p/11749894.html

基于Redis实现分布式应用限流--转

原文地址:https://my.oschina.net/giegie/blog/1525931 摘要: 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务. 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务. 前几天在DD的公众号,看了一篇关于使用 瓜娃 实现单应用限流的方案 -->原文,参考<redis in action> 实现了一个jedis版本的,

Redis+Lua实现限流

相比Redis事务来说,Lua脚本有以下优点减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输;原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用. 1.创建limit.lua文件 local key = KEYS[1] --限流KEY(一秒一个) local limit = tonumber(ARGV[1]) --限流大小 local cur

redis实现网关限流(限制API调用次数1000次/分)

添加maven依赖,使用springboot2.x版本 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId

高并发限流策略

在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹:而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待高峰或者问题解决后再打开:而有些场景并不能用缓存和降级来解决,比如稀缺资源(秒杀.抢购).写服务(如评论.下单).频繁的复杂查询(评论的最后几页),因此需有一种手段来限制这些场景的并发/请求量,即限流. 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到

聊聊高并发系统之限流特技-1 开涛

在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹:而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待高峰或者问题解决后再打开:而有些场景并不能用缓存和降级来解决,比如稀缺资源(秒杀.抢购).写服务(如评论.下单).频繁的复杂查询(评论的最后几页),因此需有一种手段来限制这些场景的并发/请求量,即限流. 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到

高并发系统之限流特技

在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹:而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待高峰或者问题解决后再打开:而有些场景并不能用缓存和降级来解决,比如稀缺资源(秒杀.抢购).写服务(如评论.下单).频繁的复杂查询(评论的最后几页),因此需有一种手段来限制这些场景的并发/请求量,即限流. 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到

聊聊高并发系统之限流特技

在开发高并发系统时,有很多手段用来保护系统:缓存.降级和限流.缓存的目的是提升系统访问速度和增大系统处理能力,可谓是抗高并发流量的银弹:而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待高峰过去或者问题解决后再打开的场景:而有些场景并不能用缓存和降级来解决,比如稀缺资源(秒杀.抢购).写服务(如评论.下单).频繁的复杂查询(评论的最后几页),因此需有一种手段来限制这些场景的并发/请求量,即限流. 限流的目的是通过对并发访问进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达