Redis 实现限流的三种方式
Java之间
共 4135字,需浏览 9分钟
·
2021-11-07 04:55
往期热门文章:
第一种:基于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、推荐 15 款常用开发工具 2、一次 QPS 翻倍的 Java 服务性能优化 3、Maven 划分模块最佳实践 4、面试官问:select......for update会锁表还是锁行? 5、Spring Boot + GraphQL 才是 API 的未来! 6、一个基于 SpringBoot2+redis+Vue 的商城管理系统,拼团、砍价、秒杀等都有,可二次开发接私活! 7、用 MySQL 实现分布式锁,你听过吗? 8、全员远程办公,半年入 1 亿美元:GitHub 的最大竞争对手上市了! 9、面试官:Spring AOP、AspectJ、CGLIB 都是什么鬼?它们有什么关系? 10、10 个 VSCode 超级摸鱼神器,确定不试一下? 关注公众号,你想要的Java都在这里
评论