Redis 实现限流的三种简单方式
往期热门文章:
2、网曝字节跳动将实行“1075”工作制!网友:这不是众所周知的嘛!守则的有多少?
3、阿里领导:手下两个应届生,一个踏实喜欢加班,一个技术强挑活,怎么选?
面对越来越多的高并发场景,限流显示的尤为重要。
第一种:基于Redis的setnx的操作
第二种:基于Redis的数据结构zset
代码如下
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("访问成功");
}
通过上述代码可以做到滑动窗口的效果,并且能保证每N秒内至多M个请求,缺点就是zset的数据结构会越来越大。实现方式相对也是比较简单的。
第三种:基于Redis的令牌桶算法
提到限流就不得不提到令牌桶算法了。
令牌桶算法提及到输入速率和输出速率,当输出速率大于输入速率,那么就是超出流量限制了。
也就是说我们每访问一次请求的时候,可以从Redis中获取一个令牌,如果拿到令牌了,那就说明没超出限制,而如果拿不到,则结果相反。
依靠上述的思想,我们可以结合Redis的List数据结构很轻易的做到这样的代码,只是简单实现
依靠List的leftPop来获取令牌
// 输出令牌
public Response limitFlow2(Long id){
Object result = redisTemplate.opsForList().leftPop("limit_list");
if(result == null){
return Response.ok("当前令牌桶中无令牌");
}
return Response.ok(articleDescription2);
}
再依靠Java的定时任务,定时往List中rightPush令牌,当然令牌也需要唯一性,所以我这里还是用UUID进行了生成
// 10S的速率往令牌桶中添加UUID,只为保证唯一性
@Scheduled(fixedDelay = 10_000,initialDelay = 0)
public void setIntervalTimeTask(){
redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
}
往期热门文章:
1、《历史文章分类导读列表!精选优秀博文都在这里了!》 2、Spring Boot + GraphQL 才是 API 的未来! 3、全员远程办公,半年入 1 亿美元:GitHub 的最大竞争对手上市了! 4、聊一聊Java 泛型通配符 T,E,K,V,? 5、各大公司程序员的工位,你中意哪一款? 6、Stackoverflow 高赞答案,为什么牛逼的程序员都不用 “ ! = null ' 做判空? 7、为什么不建议在MySQL中使用 utf8 ? 8、编写Spring MVC控制器的14个技巧!涨知识了! 9、日志打印的15个建议!血泪啊! 10、List中remove()方法的陷阱,被坑惨了!
评论