redis实现接口限流(redis令牌限流)

网友投稿 791 2022-12-31


本篇文章给大家谈谈redis实现接口限流,以及redis令牌限流对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 今天给各位分享redis实现接口限流的知识,其中也会对redis令牌限流进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

Redis实现限流策略

当系统处理能力有限时,控制流量,限流还有一个应用目的是控制用户行为,避免垃圾请求。系统要限定用户的某个行为在指定的时间里只能允许发生N次。

这个限流需求中存在一个滑动时间窗口(其实就是指定时间这个参数,定宽),可以通过zset的score来圈出这个时间窗口,只需要保留这个时间窗口,窗口之外的数据都可以砍掉。只需要保证唯一性即可,用uuid浪费空间,改用毫秒时间戳。

用zset记录用户行为历史,每个行为都会作为zset中的一个key保存下来。同一个用户的同一种行为用一个zset记录。
为了节省内存,只需要保留时间窗口内的行为记录,同时用户记录在滑动时间窗口的行为是空记录,那么这个zset就可以从内存移除。
通过统计滑动窗口内的行为数量与阈值max_count进行比较得出当前行为是否被允许

如果一定时间内的允许的数量比较大,例如限定60s操作不得超过100万次等,因为要记录时间窗口内所有行为记录,会消耗大量的存储空间。

所以,漏斗的剩余空间就代表着当前行为可以持续进行的数量,漏嘴的流水速率代表着系统允许该行为的最大频率。

问题:无法保证整个过程的原子性。从 hash 结构中取值,然后在内存里运算,再回填到hash结构,这三个过程不是原子性,需要适当加锁控制,但是加锁可能会失败,需要进行适当重试或者放弃。

Redis4.0提供限流模块Redis-Cell,使用了漏斗算法,并提供原子限流指令。
指令:cl.throttle
启动redis和模块命令

在执行限流指令时,如果被拒绝了,就需要丢弃或者重试。cl.throrrle指令直接取返回结果数组的第四个值进行sleep或者异步定时任务来重试。

基于redis的分布式RateLimiter(限流)实现

系统需要对接某IM厂商rest接口,向客户端推送消息(以及其他IM业务)
该厂商对rest接口调用有频率限制:总rest调用9000次/30s;消息推送600次/30s
系统为分布式集群,需要控制整个分布式集群总的接口调用频率满足以上限制

上篇文章 《 Guava RateLimiter源码解析 》中介绍了Guava RateLimiter的用法及原理,但为什么不直接使用Guava RateLimiter?原因有二:

为什么说选用redis是合理的?

这里完全参考Guava RateLimiter实现思路,不同的是,Guava将令牌桶数据存放于对象(内存)中,这里讲令牌桶数据存放在redis中,奉上源码 https://github.com/manerfan/m...

首先创建令牌桶数据模型

reSync函数同样是为了解决令牌桶数据更新问题,在每次获取令牌之前调用,这里不多介绍
expires函数计算redis数据过期时间。同样的例子,某接口需要分别对每个用户做访问频率限制,假设系统中存在6W用户,则至多需要在redis中创建6W条数据,对于长期运行的系统,这个数字会只增不减,这对于redis来说也是一个不小的挑战(虽然示例中的数字相对较小)。为了减轻redis压力,需要对令牌桶数据做过期处理,对于使用频率不是很高的业务场景,可以及时清理。

putDefaultPermits用于生成默认令牌桶并存入redis
permits的getter setter方法实现了redis中令牌桶的获取及更新
now用于获取redis服务器的时间,这样便能保证分布式集群中各节点对数据处理的一致性

该函数与reserveAndGetWaitLength等同,只是为了避免并发问题而添加了同步锁

需要注意,这里与Guava RateLimiter不同的是, Guava中的返回是更新前的(上次请求计算的)nextFreeTicketMicros,本次请求通过为上次请求的预消费行为埋单而实现突发请求的处理;这里返回的是由于桶中令牌不足而需要真真切切等待的时间

Redis(07)-ZSET实现简单限流

系统要限定用户的某个行为在指定的时间里只能允许发生 N 次(例如:帖子的评论数,1分钟之内只允许2次评论),可以使用 Redis 的zset数据结构来实现这个限流的功能

这个限流需求中存在一个滑动时间窗口, zset 数据结构的 score 值,可以通过 score 来圈出这个时间窗口来。而且我们只需要保留这个时间窗口,窗口之外的数据都可以砍掉。那这个 zset 的 value 填什么比较合适呢?它只需要保证唯一性即可,用 uuid 会比较浪费空间,那就改用毫秒时间戳吧。

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

为节省内存,我们只需要保留时间窗口内的行为记录,同时如果用户是冷用户,滑动时间窗口内的行为是空记录,那么这个 zset 就可以从内存中移除,不再占用空间。

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

zset 集合中只有 score 值非常重要,value 值没有特别的意义,只需要保证它是唯一的就可
以了。
因为这几个连续的 Redis 操作都是针对同一个 key 的,使用 pipeline 可以显著提升
Redis 存取效率。但这种方案也有缺点,因为它要记录时间窗口内所有的行为记录,如果这
个量很大,比如限定 60s 内操作不得超过 100w 次这样的参数,它是不适合做这样的限流
的,因为会消耗大量的存储空间 关于redis实现接口限流和redis令牌限流的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。 redis实现接口限流的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于redis令牌限流、redis实现接口限流的信息别忘了在本站进行查找喔。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:进行软件接口测试工具(进行软件接口测试工具有哪些)
下一篇:Java String 字符串常量池解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~