主流的四种限流策略,我都可以通过redis实现,干货仅此一篇

实现

  • 滑动时间窗口是将时间更加细化,上面我们是通过redis#setnx实现的。这里我们就无法通过他统一记录了。我们应该加上更小的时间单元存储到一个集合汇总。然后根据集合的总量计算限流。redis的zsett数据结构就和符合我们的需求。

  • 为什么选择zset呢,因为redis的zset中除了值以外还有一个权重。会根据这个权重进行排序。如果我们将我们的时间单元及时间戳作为我们的权重,那么我们获取统计的时候只需要按照一个时间戳范围就可以了。

  • 因为zset内元素是唯一的,所以我们的值采用uuid或者雪花算法一类的id生成器

controller

@RequestMapping(value = “/startList”,method = RequestMethod.GET)

public Map<String,Object> startList(@RequestParam Map<String, Object> paramMap) {

return testService.startList(paramMap);

}

service

String redisKey = “qpsZset”;

Integer times = 100;

if (paramMap.containsKey(“times”)) {

times = Integer.valueOf(paramMap.get(“times”).toString());

}

long currentTimeMillis = System.currentTimeMillis();

long interMills = inter * 1000L;

Long count = redisTemplate.opsForZSet().count(redisKey, currentTimeMillis - interMills, currentTimeMillis);

if (count > times) {

throw new RuntimeException(“qps refuse request”);

}

redisTemplate.opsForZSet().add(redisKey, UUID.randomUUID().toString(), currentTimeMillis);

Map<String, Object> map = new HashMap<>();

map.put(“success”, “success”);

return map;

结果测试

主流的四种限流策略,我都可以通过redis实现

  • 和固定时间窗口采用相同的并发。为什么上面也会出现临界状况呢。因为在代码里时间单元间隔比固定时间间隔采用还要大 。 上面演示固定时间窗口时间单元是1S出现了最坏情况。而滑动时间窗口设计上就应该间隔更短。而我设置成10S 也没有出现坏的情况

  • 这里就说明滑动比固定的优处了。如果我们调更小应该更加不会出现临界问题,不过说到底他还是避免不了临界出现的问题

漏桶算法


  • 滑动时间窗口虽然可以极大程度地规避临界值问题,但是始终还是避免不了

  • 另外时间算法还有个致命的问题,他无法面对突如其来的大量流量,因为他在达到限流后直接就拒绝了其他额外流量

  • 针对这个问题我们继续优化我们的限流算法。 漏桶算法应运而生

主流的四种限流策略,我都可以通过redis实现

优点

  • 面对限流更加的柔性,不再粗暴的拒绝。

  • 增加了接口的接收性

  • 保证下流服务接收的稳定性。均匀下发

缺点

  • 我觉得没有缺点。非要鸡蛋里挑骨头那我只能说漏桶容量是个短板

实现

controller

@RequestMapping(value = “/startLoutong”,method = RequestMethod.GET)

public Map<String,Object> startLoutong(@RequestParam Map<String, Object> paramMap) {

return testService.startLoutong(paramMap);

}

service

  • 在service中我们通过redis的list的功能模拟出桶的效果。这里代码是实验室性质的。在真实使用中我们还需要考虑并发的问题

@Override

public Map<String, Object> startLoutong(Map<String, Object> paramMap) {

String redisKey = “qpsList”;

Integer times = 100;

if (paramMap.containsKey(“times”)) {

times = Integer.valueOf(paramMap.get(“times”).toString());

}

Long size = redisTemplate.opsForList().size(redisKey);

if (size >= times) {

throw new RuntimeException(“qps refuse request”);

}

Long aLong = redisTemplate.opsForList().rightPush(redisKey, paramMap);

if (aLong > times) {

//为了防止并发场景。这里添加完成之后也要验证。 即使这样本段代码在高并发也有问题。此处演示作用

redisTemplate.opsForList().trim(redisKey, 0, times-1);

throw new RuntimeException(“qps refuse request”);

}

Map<String, Object> map = new HashMap<>();

map.put(“success”, “success”);

return map;

}

下游消费

@Component

public class SchedulerTask {

@Autowired

RedisTemplate redisTemplate;

private String redisKey=“qpsList”;

@Scheduled(cron=“*/1 * * * * ?”)

private void process(){

//一次性消费两个

System.out.println(“正在消费。。。。。。”);

redisTemplate.opsForList().trim(redisKey, 2, -1);

}

}

测试

  • 我们还是通过50并发循环10次访问。我们可以发现只有在一开始能达到比较高的吞吐量。在随后桶的容量满了之后。而下游水滴速率比上游请求速率慢的情况下。只能以下游恒定的速度接收访问。

  • 他的问题也暴露得很明显。针对时间窗口的不足漏桶进行的不足,但是仍是不足。无法彻底避免请求溢出的问题。

  • 请求溢出本身就是一种灾难性的问题。所有的算法目前都没有解决这个问题。只是在减缓他带来的问题

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

金三银四马上就到了,希望大家能好好学习一下这些技术点

学习视频:

大厂面试真题:

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

最后

金三银四马上就到了,希望大家能好好学习一下这些技术点

学习视频:

[外链图片转存中…(img-Dof2ZVbE-1712804131241)]

大厂面试真题:

[外链图片转存中…(img-MIFokXkT-1712804131241)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-ib8vnddC-1712804131241)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值