常用的非分布式限流算法详细说明

背景

在进行一些对外开发的api的时候,往往需要进行限流或者是控速。因为当对外开放的时候,我们无法预知流量的变化,非常有可能出现流量的迅增。而所有的服务的处理能力都是有一个极限的,一旦超过了这个阈值,那么就可能导致整个服务系统异常。一个健壮成熟的服务需要既保证可以正确接收到所有的流量,又保证服务持续正常运行,那么就需要限流系统的介入

常用的限流算法:

窗口计数法

所谓的窗口计数法,指的是可以根据时间划分出多个连续的时间窗口,通过监控时间窗口内的流量来适时的触发限速,从而保证服务接收到的流量在其阈值之内。但是,这种方法只能解决由多个时段流量累计共同导致流量超过阈值的情况。对于一瞬间的大量流量来袭依然是无能为力
在实现方式上有两种

固定窗口:

在这里插入图片描述

如上图所示,划分了两个时间窗口,0-1min为第一个,1min-2min为第二个。限制每一个时间窗口的阈值为100,即在1min的时间窗口内接收到的流量超过100了,那么就启动限速操作。

开始接收流量:
在这里插入图片描述
如上所示,一共接收了三批流量,在10s的时候接收底一批大小为30的流量。在40s的时候接收到第二批大小为50的流量。在1min10s的时候接收到了第三批大小为70的流量。
现在我们的限流思想是固定窗口,窗口阈值为100。
那么就只考虑预先设定好的0-1min和1min-2min这两个时间窗口。从上面的图示中可以看到,在0-1min这个时间窗口内,一共接收到的流量为30+50=80,低于阈值,那么服务是可以正常处理的,没有影响。在看第二个时间窗口1min-2min,接收到的流量为70,低于阈值100,那么在这个时间窗口内,服务也是可以正常处理的。但是这样就结束了吗?
可以看一下图中蓝色标注的范围,如果考虑到40s-1min20这个40s的窗口呢,他接收到的流量有50+70=120,超过了阈值,那么这个时候,服务所承受的超过了他的能力,就会有服务异常的可能。

这里有这种情况出现的可能性是因为,我们的窗口范围设置的太大,如果我们的窗口范围是30s,那么在上面的图中2min就可以切割成4个窗口,0-30s,30s-1min,1min-1min30s,1min30s-2min。如果这样切割的话,各窗口接收到的请求量就为30,50,70,0。都是低于阈值的。30,50,70三批流量的时间间隔也是大于30s的,所有不会出现高于阈值的情况
在这里插入图片描述
当窗口变成30s的时候,问题看着是解决了。那么如果50的那批流量是在50s的时候来的呢,50和70两批流量的时间间隔是20s,还是会出现时间窗口高于阈值的情况。所以在固定窗口的思想下,必然会有一些意外发生

上面介绍了固定窗口计数器的思想,其中也提到了思想的不完善性。但是所有的算法都有其适合的场景,即使他没有那么的完美
使用场景:流量波动平缓,不需要对流量进行精准控制,或者是进行整体控流的场景
优势:简单,易理解。实现起来也比较方便

滑动窗口

滑动窗口和固定窗口很像,都是将时间切割成小的时间窗口,通过监控窗口内的流量来触发限速。和固定窗口的不同在于滑动窗口是可以滑动的,即我们所监控的不是一个固定的范围,而是一个根据实际流量情况进行调整的窗口

令牌桶

令牌桶的思想是首先我们有一个桶,桶里面存放着低于桶阈值的令牌。如果有流量来的时候,就先从桶中获取令牌,只有当成功拿到令牌的时候,流量才会到达服务端。
也可以把桶理解成一个漏斗,一面放令牌,一面供流量取令牌
即令牌桶控制着流量的接收频率。
在这里插入图片描述

如上图,整个组件有4部分:

  1. 红色部分表示外部流量
  2. 绿色部分表示存储令牌的令牌桶,接收蓝色部分添加的令牌。容量为m,当令牌桶满了的时候,就不再接收令牌了
  3. 蓝色部分表示往令牌桶中添加令牌的任务,添加的速度是m/t。主动添加令牌到令牌桶,如果桶满了,多余的令牌会被废弃掉,但是下一轮会继续添加令牌,不会被桶满所影响到
  4. 紫色部分表示最终处理流量的服务器

在令牌桶算法下,服务器接收流量的速度有两个因素来决定,一个是令牌添加的频率 f,一个是流量的输入频率y。
f是一个预先设置好的频率,一般不会发生变化
y是由外部来决定

  1. 当y恒小于f的时候,流量会全部发送到服务器,令牌桶中剩余量为(f-y)t
  2. 当y恒大于f的时候,那么只有f的流量会被发送到服务器,剩下的y-f的流量会触发限速
  3. 当y和f之间没有恒定趋向的关系的时候:
    3.1 瞬间可以承受的最大流量等于此时令牌桶中令牌的数量(<=m)。需要注意,这样的强流量只有一波,因为令牌被用完之后,需要等待令牌新的补充。而令牌的放入是由专门的任务来控制的。所以不是说没了就可以立马补上的

两个速度:

  1. 峰值:令牌桶的容量
  2. 服务极限平均速度:令牌桶的添加速度

漏桶算法

所谓的漏桶算法,指的是将所有的流量放入一个已经准备好的桶,桶是有一定的容量的,如果溢出就触发限速。桶中的流量会以匀速的方式发送到服务器

在这里插入图片描述
如上图,整个组件有3部分:

  1. 红色部分表示外部流量
  2. 绿色部分表示流量的暂存地
  3. 紫色部分表示最终处理流量的服务器

在漏桶算法下,可以承受的流量取决于桶的容量。

  1. 在一瞬间可以接收到的最大流量等于此时桶的剩余空间。当桶是空的时候,可以接收到的流量是桶的容量。当桶满了的时候,那么再有流量来的时候就会触发限速。

各算法之间的比较

其实不管是令牌算法还是漏桶算法,都是对服务接收流量从平均速率的角度去进行控速。和总体控速而言,平均控速的实现逻辑更加复杂,思想更加复杂。但是可应用面也更广。对于需要持续长时间的接收不确定流量场景,如果想要做到真正可以保护服务的控速算法,总体控速是很难做到的。
漏桶算法和令牌桶算法的异同:

  1. 令牌桶是以一个恒定的速度添加令牌,漏桶是以一个恒定的速度发送流量给服务。对于频率的控制,一个被动,一个主动。
  2. 漏桶对于服务器来说更加的友好,因为当瞬间有大量流量来袭的时候,令牌是将所有的流量一起发送给服务器。而漏桶是将流量暂存在桶中,然后匀速的发送给服务器
  3. 漏桶响应更快。因为令牌桶中令牌的添加的被动的,如果是每隔t秒添加一次的话,那么在刚添加完令牌的时候,如果桶的令牌存量马上被一次性消耗完,那么在接下来的t秒内都无法在接收新的流量。但是在漏桶算法下,只有桶和服务器之间的流量流通,不涉及到其他方,所以就没有这种情况
  4. 流量突增的情况下,令牌反应更加的敏捷。因为像是第2条说的一样,当大量流量来的时候,令牌是一次发给服务,漏桶是匀速分批发送。所以如果服务器能力好,可以承受的了的话,使用令牌可以更快的消化大流量。

场景:

  1. 如果自己的系统能力还不错,对流量的响应要求比较高,可以接收突发传输,那么可以使用令牌算法。将桶的大小设计为系统能力阈值。
  2. 如果是想要把限速用在外部系统上,从而限制访问外部接口的流量,保护其他人的系统。那么可以使用漏桶算法,以匀速的速度进行请求。以避免打垮外部系统

在以后每一天的生活中,我们都会碰到不同的人,不同的事。尽管并非万事都如你我意。但只需记得,你是你自己,活你自己,和别人无关

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值