Redis 的限流、延时队列、幂等处理 “高级“应用场景

本文介绍了Redis在限流中的应用,包括固定窗口和滑动窗口计数,以及漏桶和令牌桶算法的实现。接着探讨了Redis如何实现延时队列和布隆过滤器,最后讨论了使用Redis实现幂等处理的方法,确保接口调用的幂等性。文章适合面试复习和了解Redis高级用法。
摘要由CSDN通过智能技术生成

引言

从实战层次来展开,主要是实战环节,以问题展开,应对面试场景作答【melo称其为"手撕面答"】,尽量简短,某些部分可能不会进行详细介绍。

emmm,但后边有些部分还是干脆整合在一起了,可观性好一点,不至于看得一头雾水

本篇脑图速览

Redis限流是怎么做的?

固定窗口计数

固定窗口计数是指,假设我们的限流规则是:1min内最多只能访问10次,那么固定窗口就是固定了【 1min-2min】这个窗口内,只能有10次访问 ,相应的我们就要给这个窗口维护一个计数器。 为了节省空间,其实我们不需要维护一个个窗口,只需要维护当前访问时间所在的窗口即可,以及对应的计数器,当新的访问到达了下一个窗口时,则计数器重置即可。

redis实现

用redis的话,由于有过期机制,其实设置1min过期,就可以实现计数器重置的效果了

  • redis设置一个名为qps的key,val用来计数,1min过期即可

//原子自增类 RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(redisKey, redisTemplate.getConnectionFactory()); //先自增 int qps = redisAtomicInteger.getAndIncrement(); //若是第一次访问 if(qps==0){ //设置1min过期 redisAtomicInteger.expire(1, TimeUnit.MINUTES); } if(qps>10){ throw new RuntimeException("qps超过阈值"); } 复制代码

存在的问题

由于是固定窗口,那其实存在窗口临界问题,比如用户可以在【1.5-2】这段区间访问10次,【2-2.5】这段区间也访问10次,这样就变成了1min内其实可以访问20次!看起来破坏了我们的限流规则,但由于我们是固定窗口计数,到达2的时候已经重置计数器了。

滑动窗口计数

假设我们的限流规则是:1min内最多只能访问10次,那么滑动窗口呢就是会根据你访问进来的时间,以访问时间作为区间末尾,当前时间-1min作为区间头部,相当于窗口一直在往右滑动,这样其实就能在一定程度上解决我们刚才提到的窗口临界问题

  • 当访问时间为2.5的时候,此时对于的窗口是【1.5-2.5】,计数器都能正确计数

实现

要获得一段区间,并且按时间排序,我们可以想到用ZSet来实现,能按区间查询出【当前访问时间-1min,当前访问时间】这段区间的计数

//interMills为限流时间,也就是我们这里的1min Long count = redisTemplate.opsForZSet().count(redisKey, currentTimeMillis - interMills, currentTimeMillis); 复制代码

存在的问题

其实我们只是以更小的窗口大小去移动这个区间罢了,固定窗口计数是以1min为单位去移动,滑动窗口是以1s为单位去移动,后者出现窗口临界问题的概率更小,但依然是可能出现的,比如:

1. 一开始是【1-2min】这段区间,下一秒会移动为【1min1s - 2min1s】,如果此时有人在1min这一刻,访问了10次,然后下一秒又进入下一个区间了,计数重置,在1min1s这一刻又访问了10次,依旧会出现窗口临界问题,1min内访问次数达到了20次

经评论区的小伙伴提问过后,发现其实滑动窗口算法是能够解决临界窗口问题的,当初学习时,可能只看了片面的资料,或者那个资料的实现方式不是用ZSet,而是用其他,以起点为首的区间去计算也有可能。

不过至少可以确定的是,本文用ZSet实现,以当前访问时间为区间末尾的话,确实是不会发生临界窗口问题的,非常感谢两位掘友:[吃西瓜啊] && [kb啵]

窗口临界问题小结

其实窗口临界问题,就是在即将被移出窗口的这段区间内,可能一次性访问量达到了我们的阈值,而由于要移出窗口了,计数又将重置了,所以这些访问量就相当于不会被后续统计到,那么后续再次超过阈值,就变成双倍阈值了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值