当前位置: 首页 > 图灵资讯 > 技术篇> Redis限流的三种方式

Redis限流的三种方式

来源:图灵教育
时间:2023-06-02 09:33:36

我用Redis实践了三种实现方法,可以简单地实现。

第一种:基于Redis的setnx操作

当我们使用Redis分布式锁时,我们都知道我们在CAS中依靠Setnx的指令(Compare and swap)在操作过程中,指定的key设置了过期实践(expire),限流的主要目的是在单位时间内,只有N个请求可以访问我的代码程序。因此,依靠setnx可以很容易地实现这方面的功能。

例如,我们需要在10秒内限制20个请求,因此我们可以在setnx中设置10个过期时间,当setnx的数量达到20时,我们可以达到流量限制效果。如果代码相对简单,则不显示。

当然,这种做法有很多缺点。例如,当统计1-10秒时,不能在2-11秒内统计。如果需要在N秒内统计M请求,则需要在我们的Redis中保持Nkey等

二是基于Redis的数据结构zsetet

事实上,限流涉及的最重要的是滑动窗口,上面还提到了1-10是如何变成2-11的。事实上,起始值和终端值都是+1。

如果我们使用Redislist数据结构,我们可以很容易地实现这个功能

我们可以将请求构建成一个zset数组。当每个请求进来时,value是唯一的,可以用UUUID生成,score可以用当前时间戳表示,因为score可以用来计算当前时间戳中的请求数量。zset数据结构还提供了range方法,让我们在两个时间戳中轻松获得多少请求。

代码如下

public Response limitFlow(){        Long currentTime = new Date().getTime();        System.out.println(currentTime);        if(redisTemplate.hasKey("limit")) {            Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime -  intervalTime, currentTime).size();        // intervaltime是限流时间             System.out.println(count);            if (count != null && count > 5) {                return Response.ok(“每分钟最多只能访问5次”;            }        }        redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);        return Response.ok(访问成功);    }

滑动窗口的效果可以通过上述代码来实现,M请求最多可以在每N秒内保证。缺点是zset的数据结构会越来越大。实现方法相对简单。

第三种:基于Redis的令牌桶算法

说到限流,不得不提到令牌桶算法。

令牌桶算法提到输入速率和输出速率,当输出速率大于输入速率时,就超过了流量限制。

也就是说,每次我们访问请求时,我们都可以从Redis中获得令牌。如果我们获得令牌,这意味着没有超过限制。如果我们得不到它,结果是相反的。

依靠上述思想,我们可以很容易地结合Redis的List数据结构来实现这样的代码,只是简单地实现

依靠ListleftPop获取令牌

// publicicc输出令牌 Response limitFlow2(Long id){        Object result = redisTemplate.opsForList().leftPop("limit_list");        if(result == null){            return Response.ok(“当前令牌桶中无令牌”;        }        return Response.ok(articledescription2);    }

然后依靠Java的定时任务,定期到Listrightpush令牌。当然,令牌也需要独特性,所以我在这里生成了UUID

// 10S的速率将UUID添加到令牌桶中,以确保唯一性    @Scheduled(fixedDelay = 10_000,initialDelay = 0)    public void setIntervalTimeTask(){        redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());    }

综上所述,代码一开始并不难实现。对于这些限流方式,我们可以将上述代码添加到AOP或filter中,以实现界面的限流,最终保护您的网站。