当前位置: 首页 > 后端技术 > Java

Redis限流的3种方法,还有谁不会!

时间:2023-04-02 09:33:09 Java

面对越来越多的高并发场景,限流显示显得尤为重要。当然,实现限流的方式有很多种。Redis具有非常强大的功能。我用Redis实践过三种实现方式,都可以用比较简单的方式实现。Redis不仅可以做限流,还可以做数据统计,附近的人等功能,可能以后会写。第一种:基于Redis的setnx操作我们在使用Redis的分布式锁的时候,都知道依赖于setnx指令。在操作CAS(Compareandswap)时,我们同时设置了指定的key。过期实践(expire),我们限流的主要目的是在单位时间内只有N个请求可以访问我的代码程序。所以依靠setnx可以轻松做到这个功能。比如我们需要在10秒内限制20次请求,那么我们可以在setnx的时候设置过期时间为10,当setnx请求次数达到20次时,就达到了限流的效果。代码比较简单,就不展示了。当然,这种方法有很多缺点。比如在数1-10秒的时候,不可能数到2-11秒以内。如果我们需要在N秒内统计M个请求,那么我们需要在我们的Redis中保存N个key等等。第二种:基于Redis的数据结构zset其实涉及到限流的最主要的就是滑动窗口。上面也提到了1-10如何变成2-11。实际上,起始值和结束值都是+1。而如果我们使用Redis的list数据结构,就可以轻松实现这个功能。我们可以将请求放入zset数组。每次请求进来的时候,value保持唯一,可以通过UUID生成,score可以用当前时间戳表示,因为score可以用来计算有多少在当前时间戳内。请求的数量。zset数据结构还提供了range方法,方便我们获取两个时间戳内有多少请求。代码如下:publicResponselimitFlow(){LongcurrentTime=newDate().getTime();System.out.println(当前时间);if(redisTemplate.hasKey("limit")){整数计数=redisTemplate.opsForZSet().rangeByScore("limit",currentTime-intervalTime,currentTime).size();//intervalTime为限流时间System.out.println(count);if(count!=null&&count>5){returnResponse.ok("每分钟最多5次访问");}}redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);returnResponse.ok("Accesssuccessful");}通过上面的代码,可以实现滑动窗口的效果,每N秒最多可以保证M个请求。缺点是zset的数据结构会越来越大。实现相对简单。第三种:基于Redis的令牌桶算法说到限流,就不得不提到令牌桶算法。令牌桶算法是指输入速率和输出速率。当输出速率大于输入速率时,则超过流量限制。也就是说,我们每访问一个请求,就可以从Redis中获取一个token。如果拿到token,就说明没有超过限制,如果拿不到,结果正好相反。依靠以上思路,我们可以结合Redis的List数据结构轻松实现这样的代码,只需要简单实现List的leftPop获取tokens//输出tokenspublicResponselimitFlow2(Longid){Objectresult=redisTemplate.opsForList().leftPop("limit_list");if(result==null){returnResponse.ok("当前令牌桶中没有令牌");}returnResponse.ok(articleDescription2);}然后依赖JavaTimedtask,定时将rightPushtoken放在List中,当然token也需要是唯一的,所以我这里还是使用UUID来生成//添加UUID以10S的速率传给令牌桶,只为保证唯一性@Scheduled(fixedDelay=10_000,initialDelay=0)publicvoidsetIntervalTimeTask(){redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());}综上所述,代码实现一开始并不是很难,对于这些限流方式,我们可以将上面的代码添加到AOP或者filter中,实现接口限流,最终保护你的网站。Redis其实还有很多其他用途。它的作用不仅仅是缓存,还有分布式锁的作用。他的数据结构不仅仅是String、Hash、List、Set、Zset。有兴趣的可以了解一下他的GeoHash算法;BitMap、HLL和Bloomfilter数据(Redis4.0后加入,可以直接用Docker安装redislabs/rebloom)结构。如果您有任何问题,请留言讨论。