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

2023-02-02 0 449

结语

在web开发中机能是终极目标,除机能之外网络管理和防雷是重头了。即使在中文网站运转期间可能会即使突然的用户数量引致业务极度、也有可能遭遇别人蓄意反击所以他们的USB需要对网络流量展开管制。通称的QPS也是对网络流量的一类叙述特别针对开闭现在多半应该是副本桶演算法,即使它能确保更多的客运量。除副本桶演算法除了他的创建者漏桶演算法和单纯的算数演算法上面他们来看看这三种演算法

一般来说天数询问处演算法

一般来说天数询问处演算法也能叫作单纯算数演算法。网路上有很多都将算数演算法原则上释放出来出来。但是本栏认为算数演算法是一类价值观,而一般来说天数询问处演算法是他的一类同时实现包括上面翻转天数询问处演算法也是算数演算法的一类同时实现。即使算数假如不和天数展开存取的话所以丧失了开闭的其本质了。就变为了婉拒了
主流的四种限流策略,我都可以通过redis实现

缺点

在一般来说的天数内出现网络流量外溢能立刻作出开闭。每一天数询问处不会此消彼长在天数模块内确保控制系统的稳定。确保的天数模块内控制系统的客运量下限

缺点

正像库尔一样,他的最大问题是云里。在零点状态最坏情形会受到三倍网络流量允诺除零点的情形,除了一类是在一个模块天数Q1567A后期假如迅速地耗用完允诺共振频率。所以剩的天数Sonbhadra无法允诺。这样就会即使一刹那的网络流量引致一段天数内控制系统不需用。这在网络高需用的控制系统中是不能接受的。

同时实现

好了,关于基本原理介绍及优劣他们已经了解了。上面他们亲自动手同时实现它首先他们在同时实现这种算数时,采用redis是非常好的选择。这里他们透过redis同时实现

controller

@RequestMapping(value = “/start”,method = RequestMethod.GET) public Map<String,Object> start(@RequestParam Map<String, Object> paramMap) { return testService.startQps(paramMap); }

service

@Override publicMap<String, Object> startQps(Map<String, Object> paramMap) { //根据前端传递的qps上线 Integer times = 100; if(paramMap.containsKey(“times”)) { times = Integer.valueOf(paramMap.get(“times”).toString()); } String redisKey = “redisQps”; RedisAtomicInteger redisAtomicInteger = newRedisAtomicInteger(redisKey, redisTemplate.getConnectionFactory()); int no = redisAtomicInteger.getAndIncrement();//设置天数一般来说天数询问处长度 1S if (no == 0) { redisAtomicInteger.expire(1, TimeUnit.SECONDS); } //判断是否超限 time=2 表示qps=3 if (no > times) { throw new RuntimeException(“qps refuse request”); } //返回成功告知 Map<String, Object> map =new HashMap<>(); map.put(“success”, “success”); return map; }

结果测试

主流的四种限流策略,我都可以通过redis实现
他们设置的qps=3 , 他们能看到五个并发进来后前三个正常访问,后面两个就失败了。稍等一段天数他们在并发访问,前三个又能正常访问。说明到了下一个天数询问处
主流的四种限流策略,我都可以通过redis实现

翻转天数询问处演算法

特别针对一般来说天数询问处的缺点–零点值出现双倍网络流量问题。 他们的翻转天数询问处就产生了。其实很好理解,是特别针对一般来说天数询问处,将天数询问处统计从原来的一般来说间隔变为更加细度化的模块了。在上面他们一般来说天数询问处演示中他们设置的天数模块是1S 。 特别针对1S他们将1S拆成天数戳。一般来说天数询问处是统计模块随着时间的推移不断向后展开。而翻转天数询问处是他们认为的想象出一个天数模块按照相对论的价值观将天数一般来说,他们的抽象天数模块自己移动。抽象的天数模块比实际的天数模块更小。读者能看下上面的动图,就能理解了。
主流的四种限流策略,我都可以通过redis实现

缺点

实质上是一般来说天数询问处演算法的改进。所以一般来说天数询问处的缺点是他的缺点。内部抽象一个翻转的天数窗,将天数更加小化。存在边界的问题更加小。客户感知更弱了。

缺点

不管是一般来说天数询问处演算法还是翻转天数询问处演算法,他们都是基于算数器演算法展开优化,但是他们对待开闭的思路太粗暴了。为什么说粗暴呢,未开闭他们正常放行。一旦达到开闭后就会直接婉拒。这样他们会损失一部分允诺。这对于一个产品来说不太友好

同时实现

翻转天数询问处是将时间更加细化,上面他们是透过redis#setnx同时实现的。这里他们就无法透过他统一记录了。他们应该加上更小的天数模块存储到一个集合汇总。然后根据集合的总量计算开闭。redis的zsett数据结构就和符合他们的需求。围就能了。即使zset内元素是唯一的,所以他们的值采用uuid或者雪花演算法一类的id生成器

controller

@RequestMapping(value = “/startList”,method = RequestMethod.GET) public Map<String,Object> startList(@RequestParamMap<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实现

缺点

面对开闭更加的柔性,不再粗暴的婉拒。增加了USB的接收性确保下流服务接收的稳定性。均匀下发

缺点

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

同时实现

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 publicMap<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”); returnmap; }

下游消费

@Component public class SchedulerTask { @Autowired RedisTemplate redisTemplate; privateString redisKey=“qpsList”; @Scheduled(cron=“*/1 * * * * ?”) private void process(){ //一次性消费两个 System.out.println(“正在消费。。。。。。”); redisTemplate.opsForList().trim(redisKey, 2, –1); } }

测试

他们还是透过50并发循环10次访问。他们能发现只有在一开始能达到比较高的客运量。在随后桶的容量满了之后。而下游水滴速率比上游允诺速率慢的情形下。只能以下游恒定的速度接收访问。他的问题也暴露得很明显。特别针对天数询问处的不足漏桶展开的不足,但是仍是不足。无法彻底避免允诺外溢的问题。允诺外溢本身是一类灾难性的问题。所有的演算法目前都没有解决这个问题。只是在减缓他带来的问题
主流的四种限流策略,我都可以通过redis实现

副本桶演算法

副本桶和漏桶法是一样的。只不过将桶的作用方向改变了一下。漏桶的出水速度是恒定的,假如网络流量突然增加的话他们就只能婉拒入池但是副本桶是将副本放入桶中,他们知道正常情形下副本是一串字符当桶满了就婉拒副本的入池,但是面对高网络流量的时候正常加上他们的超时天数就留下足够长的天数生产及消费令牌了。这样就尽可能地不会造成允诺的婉拒最后,不论是对于副本桶拿不到副本被婉拒,还是漏桶的水满了外溢,都是为了确保大部分网络流量的正常使用,而牺牲掉了少部分网络流量public Map<String, Object> startLingpaitong(Map<String, Object> paramMap) { String redisKey = “lingpaitong”; Stringtoken = redisTemplate.opsForList().leftPop(redisKey).toString();//正常情形需要验证是否合法,防止篡改 if(StringUtils.isEmpty(token)) {throw new RuntimeException(“副本桶婉拒”); } Map<String, Object> map = new HashMap<>(); map.put(“success”, “success”); return map; } @Scheduled(cron=“*/1 * * * * ?”) private void process(){ //一次性生产两个System.out.println(“正在消费。。。。。。”); for (int i = 0; i < 2; i++) { redisTemplate.opsForList().rightPush(redisKey, i); } }

原文链接:

https://juejin.cn/post/6967704472109711367

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务