限流方案常用的算法讲解

1、令牌桶算法

  token bucket 令牌桶算法是目前应用最为广泛的限流算法,顾名思义,他有以下两个关键角色: 

    1、令牌 获取到令牌的 Request 才会被处理,其他 Request 要么排队要么被直接丢弃

    2、桶 用来装令牌的地方,所有 Request 都从这个桶里面获取令牌

  了解了这两个角色之后,就来看一下令牌桶算法:

  

   令牌生成

     这个流程设计到令牌生成器和令牌桶,前面我们提到过令牌桶是一个装令牌的地方,既然是个桶那么必然有一个容量,也就是令牌桶所能容纳的令牌数量是一个固定的数值。

    对于令牌生成器来说,它会根据一个预定的速率向桶中添加令牌,比如我们可以配置让它以每秒100个请求的速率发放令牌,或者每分钟50个。注意这里的发放速度是匀速的,也就是说这50个令牌并非是在每个时间窗口刚开始的时候一次性发放,而是在这个时间窗口内匀速发放。

    在令牌发放器就是一个水龙头,假如在下面接水的桶子满了,那么水自然就留到外面了。在令牌方法过程中也一样,令牌桶的容量是有限的,如果当前已经放满了额定的容量的令牌,那么新来的令牌就会被丢弃。

  令牌获取

    每个访问请求到来后,必须获取到一个令牌才能执行后面的逻辑。假如令牌的数量少,而访问请求较多的情况下,一部分请求自然无法拿到令牌,那么这个时候我们可以设置一个“缓冲队列”来暂存这些多余的令牌。

    缓冲队列其实是一个可选项,并不是所有的应用了令牌桶算法的程序都会实现队列。当有缓存队列存在的情况下,那些暂时没有获取到令牌的请求将被放到这个队列中排队,直到新的令牌产生后,再从队列头部拿出一个请求来匹配令牌。

    当队列已满的情况下,这部分访问请求将被丢弃。在实际应用中我们还可以给这个队列加一系列的特效,比如设置队列中请求的存活时间,或者将队列改造为 PriorityQueue ,根据某种优先级排序,而不是先进先出。

2、漏桶算法

  

 

   漏桶算法的前半段和令牌桶类似,但是操作的对象不同,令牌桶是将令牌放入桶里,而漏桶是将访问请求的数据包放到桶里。同样的是,如果桶满了,那么后面新来的数据包将被丢弃。

  漏桶算法的后半程是有鲜明特色的,它永远只会以一个恒定的速率将数据包从桶内流出。打个比方,如果我设置了漏桶可以存放100个数据包,然后流出速度是1s一个,那么不管数据包以什么速度流入桶里,也不管桶里有多少数据包,漏桶能保证这些数据包永远以1s一个的恒定速度被处理。

  漏桶 VS 令牌桶的区别

  根据它们各自的特点不难看出,这两种算法都有一个“恒定”的速度和“不定”的速度。令牌桶是以恒定的速度创建令牌,但是访问请求获取令牌的速度“不定”,反正有多少令牌发多少,令牌没了就干等。而漏桶是以“恒定”的速率处理请求,但是这些请求流入桶的速度是”不定“的。

  从这两个特点来说,漏桶的天然特性决定了它不会突发流量,就算每秒1000个请求到来,那么它对后台服务输出的访问速率永远恒定。而令牌桶则不同,其特性可以”预存“一定量的令牌,因此在应对突发流量的时候可以在短时间消耗所有的领票,其突发流量处理效率会比漏桶高,但是导向后台系统的压力也会相应增多。

3、活动窗口

  Rolling Window,穿上你的滑板鞋,跟我一起摇摆。

  

 

   上图中黑色的大框就是时间窗口,我们设定窗口时间为5秒,它会随着时间推移向后滑动。我们将窗口内的时间划分为五个小格子,每个小格子代表1秒钟,同时这个格子还包含一个计数器,用来计算在当前时间内访问的请求数量。那么这个时间窗口内的总访问量就是所有格子计数器累加后的数值。

  比如说,我们在每一秒内有5个用户访问,第5秒内有10个用户访问,那么0到5秒这个时间窗口内访问量就是15.如果我们的接口设置了时间窗口内访问上限是20,那么当时间到第6秒的时候,这个时间窗口内的计数总和就变成了10,因为1秒的格子已经退出了时间窗口,因此在第6秒内可以接收的访问量就是 20-10=10个。

  滑动窗口其实也是一种计算器算法,它有一个显著特点,当时间窗口的跨度越长时,限流效果就越平滑。打个比方,如果当前时间窗口只有两秒,而访问请求全部集中在第1秒的时候,当时间向后滑动1秒后,当前窗口的计算量将发生较大的变化,拉长时间窗口可以降低这种情况的发生概率。

 

posted @ 2022-08-05 17:19  放手解脱  阅读(87)  评论(0编辑  收藏  举报