高并发下漏洞桶限流设计方案 - Redis

2024-05-24 14:38

本文主要是介绍高并发下漏洞桶限流设计方案 - Redis,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:低调的码农
链接:https://juejin.im/post/5d11cef9e51d4550a629b2a6
来源:掘金

背景

在我们做社区的时候,经常会出现发水帖的同学。对于这种恶意刷帖的,我们的运营同学很是头疼,而且这种还不能在网关进行ip之类的过滤,只能基于单个单个用户进行处理,我们经常策略就是:每分钟发帖次数不能超过2个,超过后就关小黑屋10分钟。

出现场景:

  1. 上面讲的发帖的防刷机制。

  2. 广告流量的防刷。

  3. 接口请求失败进行熔断机制处理。

  4. ......

解决方案

对于这种“黑恶”请求,我们必须要做到是关小黑屋,当然有的系统架构比较大的,在网关层面就已经进行关了,我们这里是会在业务层来做,因为咱业务不是很大,当然同学们也可以把这个移植到网关层,这样不用穿透到我们业务侧,最少能够减少我们机房内部网络流量。

流程图

流程说明

  1. 接口发起请求,服务端获取这个接口用户唯一标识(用户id,电话号码...).

  2. 判断该用户是否被锁住,如果锁住就直接返回错误码。

  3. 未锁住就将该请求标记,亦或者叠加(叠加有坑,往下面看)。

  4. 进行计算当前用户在一定时间内是否超过我们设置的阈值。如果未超过直接返回。

  5. 如果超过,那么就进行锁定,再返回,下次请求的时候再进行判断。

具体方案

以我们场景为例子,使用Redis来做分布式锁和原子计数器,时间内叠加,判断叠加值是否超过阈值。

这个方案,在很多人设计的时候,都会考虑,看起来也没有太大问题,主要流程是:

  1. 假设我们使用Redis来进行原子计数,每次进来我们进行incr操作,并且将我们的key设置为一个阈值过期时间.

//将我们用户请求量叠加1$request_nums = Redis::incr('user:1:request:nums',1);//第一次叠加,设置key的过期时间if ($request_nums == 1){    Redis::expire('user:1:request:nums',300);}

if($request_nums > 10){//加入小黑屋,下次再进来就要锁定判断}
  1. 每次请求会优先进行叠加,然后在这个有效区间内,计算我们的请求次数,如果请求次数超过阈值,那么关小黑屋,要是没有就继续走下去。

问题:咋一看是没有问题,每次计算都在我的区间内,能够保证一个区间内的请求量是没问题的,而且还是要我们Redis的原子计数器,但是这里有一个问题是,一个用户两个时间段内都没有问题,但是跨时间段这个点是没有考虑的。

那么有办法解决这个时间推移问题造成时间段计算量不精准的问题吗?

答案是肯定有,我接下来是使用了Redis的有序集合来做。

请求不进行时间段区分,直接写入有序集合

大致流程:

  1. 每次请求就写入有序集合里面,集合的sorce值是当前毫秒时间戳(防止秒出现重复),可以认为每一次请求就一个时间戳在里面。

  2. 从集合里面去掉10分钟以前所有的集合数据。然后计算出当前的集合里面数量

  3. 根据这个数量来与我们阈值做大小判断,如果超过就锁住,否则继续走下去

//将我们时间戳写入我们redis的有序集合里面 Redis::zadd('user:1:request:nums',1561456435,'1561456435.122');//设置key的过期时间为10分钟Redis::expire('user:1:request:nums',300);//删除我们10分钟以前的数据Redis::ZREMRANGEBYSCORE('user:1:request:nums',0,1561456135);//获取里面剩下请求个数$request_nums=(int)Redis::zcard(self::TIMELINE_ELEVEL_KEY);if($request_nums >= 10){//加入小黑屋,下次再进来就要锁定判断}...

因为我们不是单纯记录数值,而是会将请求时间记录下来,那么随着时间推移,我们的请求数统计是不会断代的。

总结

  1. 在开始的时候,我一直在想第一个方案的问题所在,后来在讨论方案时候,总是发现时间移动,数值应该是会更改,可在第一个方案内,我们的请求量是不会更改,我们时间段已经固化成数值了。

  2. 整体的方案设计我们使用到的Redis的有序集合来做,当然有更好的方案欢迎大家来推荐哈,这个对于redis的读写压力很大的,但是作为临时的数据存储,这个场景还是比较符合。

  3. 我们redis的所有操作建议使用原子化来进行,这个可以使用官方提供的lua脚本来将多个语句合并成一个语句,并且lua执行速率也是很高。

这篇关于高并发下漏洞桶限流设计方案 - Redis的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/998690

相关文章

redis群集简单部署过程

《redis群集简单部署过程》文章介绍了Redis,一个高性能的键值存储系统,其支持多种数据结构和命令,它还讨论了Redis的服务器端架构、数据存储和获取、协议和命令、高可用性方案、缓存机制以及监控和... 目录Redis介绍1. 基本概念2. 服务器端3. 存储和获取数据4. 协议和命令5. 高可用性6.

Redis的数据过期策略和数据淘汰策略

《Redis的数据过期策略和数据淘汰策略》本文主要介绍了Redis的数据过期策略和数据淘汰策略,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录一、数据过期策略1、惰性删除2、定期删除二、数据淘汰策略1、数据淘汰策略概念2、8种数据淘汰策略

Redis存储的列表分页和检索的实现方法

《Redis存储的列表分页和检索的实现方法》在Redis中,列表(List)是一种有序的数据结构,通常用于存储一系列元素,由于列表是有序的,可以通过索引来访问元素,因此可以很方便地实现分页和检索功能,... 目录一、Redis 列表的基本操作二、分页实现三、检索实现3.1 方法 1:客户端过滤3.2 方法

Python中操作Redis的常用方法小结

《Python中操作Redis的常用方法小结》这篇文章主要为大家详细介绍了Python中操作Redis的常用方法,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解一下... 目录安装Redis开启、关闭Redisredis数据结构redis-cli操作安装redis-py数据库连接和释放增

redis防止短信恶意调用的实现

《redis防止短信恶意调用的实现》本文主要介绍了在场景登录或注册接口中使用短信验证码时遇到的恶意调用问题,并通过使用Redis分布式锁来解决,具有一定的参考价值,感兴趣的可以了解一下... 目录1.场景2.排查3.解决方案3.1 Redis锁实现3.2 方法调用1.场景登录或注册接口中,使用短信验证码场

Redis 多规则限流和防重复提交方案实现小结

《Redis多规则限流和防重复提交方案实现小结》本文主要介绍了Redis多规则限流和防重复提交方案实现小结,包括使用String结构和Zset结构来记录用户IP的访问次数,具有一定的参考价值,感兴趣... 目录一:使用 String 结构记录固定时间段内某用户 IP 访问某接口的次数二:使用 Zset 进行

解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)

《解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)》该文章介绍了使用Redis的阻塞队列和Stream流的消息队列来优化秒杀系统的方案,通过将秒杀流程拆分为两条流水线,使用Redi... 目录Redis秒杀优化方案(阻塞队列+Stream流的消息队列)什么是消息队列?消费者组的工作方式每

Redis如何使用zset处理排行榜和计数问题

《Redis如何使用zset处理排行榜和计数问题》Redis的ZSET数据结构非常适合处理排行榜和计数问题,它可以在高并发的点赞业务中高效地管理点赞的排名,并且由于ZSET的排序特性,可以轻松实现根据... 目录Redis使用zset处理排行榜和计数业务逻辑ZSET 数据结构优化高并发的点赞操作ZSET 结

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

Redis多种内存淘汰策略及配置技巧分享

《Redis多种内存淘汰策略及配置技巧分享》本文介绍了Redis内存满时的淘汰机制,包括内存淘汰机制的概念,Redis提供的8种淘汰策略(如noeviction、volatile-lru等)及其适用场... 目录前言一、什么是 Redis 的内存淘汰机制?二、Redis 内存淘汰策略1. pythonnoe