基于redis实现的四种常见的限流策略

在web开发中功能是基石,除了功能以外运维和防护就是重头菜了。因为在网站运行期间可能会因为突然的访问量导致业务异常、也有可能遭受别人恶意攻击

所以我们的接口需要对流量进行限制。俗称的QPS也是对流量的一种描述

针对限流现在大多应该是令牌桶算法,因为它能保证更多的吞吐量。除了令牌桶算法还有他的前身漏桶算法和简单的计数算法

下面我们来看看这四种算法

固定时间窗口算法

固定时间窗口算法也可以叫做简单计数算法。网上有很多都将计数算法单独抽离出来。但是笔者认为计数算法是一种思想,而固定时间窗口算法是他的一种实现

包括下面滑动时间窗口算法也是计数算法的一种实现。因为计数如果不和时间进行绑定的话那么失去了限流的本质了。就变成了拒绝了

image-20210508103957917

优点

在固定的时间内出现流量溢出可以立即做出限流。每个时间窗口不会相互影响

在时间单元内保障系统的稳定。保障的时间单元内系统的吞吐量上限

缺点

正如图示一样,他的最大问题就是临界状态。在临界状态最坏情况会受到两倍流量请求

除了临界的情况,还有一种是在一个单元时间窗内前期如果很快的消耗完请求阈值。那么剩下的时间将会无法请求。这样就会因为一瞬间的流量导致一段时间内系统不可用。这在互联网高可用的系统中是不能接受的。

实现

好了,关于原理介绍及优缺点我们已经了解了。下面我们动手实现它

首先我们在实现这种计数时,采用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 public Map<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 = new RedisAtomicInteger(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; } 结果测试

image-20210508135718284

我们设置的qps=3 , 我们可以看到五个并发进来后前三个正常访问,后面两个就失败了。稍等一段时间我们在并发访问,前三个又可以正常访问。说明到了下一个时间窗口

image-20210508140028835

image-20210508141549335

滑动时间窗口算法

针对固定时间窗口的缺点--临界值出现双倍流量问题。 我们的滑动时间窗口就产生了。

其实很好理解,就是针对固定时间窗口,将时间窗口统计从原来的固定间隔变成更加细度化的单元了。

在上面我们固定时间窗口演示中我们设置的时间单元是1S 。 针对1S我们将1S拆成时间戳。

固定时间窗口是统计单元随着时间的推移不断向后进行。而滑动时间窗口是我们认为的想象出一个时间单元按照相对论的思想将时间固定,我们的抽象时间单元自己移动。抽象的时间单元比实际的时间单元更小。

读者可以看下下面的动图,就可以理解了。

基于redis实现的四种常见的限流策略

优点

实质上就是固定时间窗口算法的改进。所以固定时间窗口的缺点就是他的优点。

内部抽象一个滑动的时间窗,将时间更加小化。存在边界的问题更加小。客户感知更弱了。

缺点

不管是固定时间窗口算法还是滑动时间窗口算法,他们都是基于计数器算法进行优化,但是他们对待限流的策略太粗暴了。

为什么说粗暴呢,未限流他们正常放行。一旦达到限流后就会直接拒绝。这样我们会损失一部分请求。这对于一个产品来说不太友好

实现

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpzdp.html