vlambda博客
学习文章列表

服务限流的作用及实现

限流的主要目的是通过限制并发访问数或者限制一个时间窗口内允许处理的请求数量来保护系统,一旦达到限制数量则对当前请求进行处理采取对应的拒绝措施,比如跳转到错误页面、拒绝请求、进入排队系统、降级等。从本质上来说,限流的主要作用是损失一部分用户的可用性,为大部分用户提供稳定可靠的服务,比如系统当前能够处理的并发数是10万,如果此时来了12万用户,那么限流机制会保证为10万用户提供正常服务。


在实际开发中,限流几乎无处不在。

  • 在Nginx层添加限流模块限制平均访问速度。


  • 通过设置数据库连接处、线程池的大小来限制总的并发数。


  • 通过Guava提供的Ratelimiter限制接口的访问速度。


  • TCP通信协议中的流量整形。


要实现限流,最重要的就是限流的算法。


计数器算法


计算器算法是一种比较简单的限流实现算法,在指定周期内累加访问次数,当访问次数达到设定的阈值时,触发限流策略,当进入下一个时间周期时将访问次数清零,重新计数。

如上图,限定了每一分钟能够处理的总的请求数为100,在第一个一分钟内,一共请求了60次,接着到第二个一分钟,counter又从0开始计数,如果在一分半钟的时候,已经达到最大限流的阈值,这个时候后续的所有请求都会被拒绝。这种算法可以用在短信发送的频次限制上,比如限制同一个用户一分钟内触发短信的次数。

服务限流的作用及实现

这种算法存在一个临界问题,如上图,在第一分钟的0:50s和第二分钟的1:10s这2个时间段分别出现了100个请求,整体上来看就会出现20s内的请求量达到200个,超出了设置的阈值。


滑动窗口算法


为了解决计数器算法带来的临界问题,所以引入了滑动窗口算法。滑动窗口算法是一种流量控制技术,在TCP网络协议中,就采用了滑动窗口算法来解决网络拥塞的情况。


滑动窗口算法的原理是在固定窗口中分割出多个小时间的窗口,分别在每个小时间窗口中记录访问次数,然后根据时间将窗口往前滑动并删除过期的小时间窗口,最终只需要统计滑动窗口范围内的所有小时间窗口总的计数即可。

服务限流的作用及实现

如上图,我们将一分钟拆分成4个小时间窗口,每个小时间窗口最多能够处理25个请求,并且通过虚线框表示滑动窗口的大小。同时滑动窗口会随着时间往前移动,比如前面15S结束之后,窗口会滑动到15s ~ 45s这个范围,然后在新的窗口中重新统计数据,这种方式很好的解决了固定窗口算法的临界值问题。Sentinel就是采用滑动窗口算法来实现限流的。


令牌通限流算法


令牌桶是网络流量整形和速率限制中最常用的一种算法,对于每一个请求,都需要从令牌桶中获取一个令牌,如果没有获得令牌,则需要触发限流策略。

如上图,系统会以一个恒定的速率往固定容量的令牌桶中放入令牌,如果此时有客户端请求过来,则需要先从令牌桶中得到令牌以获得访问资格。


由于令牌桶有固定的大小,当请求小于令牌桶生成速度时,令牌桶会被填满,所以令牌桶能够处理突发流量,也就是在短时间内新增的流量系统能够正常处理,这是令牌桶的特性。


漏桶限流算法


漏桶限流算法的主要作用是控制数据注入网络的速度,平滑网络上的突发流量。

在漏桶算法内部同样维护一个容器,这个容器会以恒定速度出水,不管上面的水流速度多快,漏桶水滴的流出速度始终保持不变。实际上消息中间件就使用了漏桶限流的思想,不管生产者的量有多大,消息的处理能力取决于消费者。

漏桶限流算法和令牌桶限流算法的实现原理相差不大,最大的区别是漏桶无法处理短时间内的突发流量,漏桶限流算法是一种恒定速度的限流算法。