认识限流以及限流算法
一、什么是限流
什么是限流?说白了就是限制用户请求的访问速率,如果不进行限流的话,一旦热点业务在某个时刻突然有大量的请求涌入,会导致大量的服务器资源被占用,进而可能会引发响应速度变慢,甚至可能会导致服务器宕机。限流不仅可以应对热点的突发请求,同时也可以限制某些恶意的攻击请求。
二、常见的限流算法
常见的限流算法有如下几种:
- 固定窗口计数器算法
- 滑动窗口计数器算法
- 漏桶算法
- 令牌桶算法
下面我们一个一个来看:
2.1 固定窗口计数器算法
固定窗口计数器算法就是根据固定长短的时间将我们的时间线划分为一个个等长的时间窗口,比如说按照1分钟进行划分,每个1分钟就对应一个时间窗口,窗口通过一个计数器来限制通过当前窗口的最大请求数量,比如说限制为100,那么就意味着当前窗口最多只能通过100个请求,超出这个限制的请求会被无情丢弃,当到达我们的下一个窗口的时候,计数器会被重置。

这种限流算法比较简单直观,但是它在限流的处理上不够平滑,思考以下这种情况:假设按照上面的1分钟作为间隔进行窗口划分,如果当前窗口在最后10秒内涌入100个请求,又在下一个窗口的前10秒涌入100个请求,相当于请求会被全部集中在这20秒内处理,而在窗口的其余部分则完全不可用,这就是窗口边界的突刺问题。
2.2 滑动窗口计数器算法
滑动窗口计数器算法可以说是上面固定窗口计数器算法的升级版,它没有所谓的窗口边界的突刺问题。那么它具体是怎么工作的呢?首先,该算法维护了两个计数器,分别是:
- prev_count:上一个窗口的请求数
- cur_count:当前窗口的请求数
假设窗口大小为T,当前窗口已经过去了elapsed,则:
当前窗口已过的比例=p=elapsed/T
上一窗口剩余比例=1-p=(T-elapsed)/T
则我们可以大概估算最近T时间内的请求数为:
estimated=cur_count+prev_count*(1-p)
那么,判断当前是否放行的标准就是:
如果estimated+1 > limit,则拒绝
否则放行,并把cur_count加1
其实这种算法我们可以把它想象成是在上一个固定窗口的基础上面再放了一个随着时间缓慢向前移动的动态窗口,这个动态窗口的大小和固定窗口的大小是一致的。

这种算法比上面的固定窗口算法要复杂一些,但是相对来说更加平滑,并且没有窗口边界的突刺问题,但是因为这个是近似精确,所以可能导致一些本可允许的请求被拒绝掉。
2.3 漏桶算法
漏桶算法,顾名思义,就是一个会漏水的桶,上面一个洞,下面一个洞,上面进水,下面出水,当然,这个水就是我们的请求,这个桶是容量有限的,当桶满了,这个时候再往里面加水,水就会漏出去(请求丢失),这个桶是以“固定速率”往下漏水的,当桶空了,就会停止漏水。

这种算法的有点很明显,它可以很平稳的消费请求(固定速率),但是这同样意味着它无法应对大量的突发请求,除此之外,如果桶进水的速率持续大于出水的速率,那么就会造成持续的请求丢失,降低服务质量。
2.4 令牌桶算法
令牌桶也是一个桶,但是它不会“漏水”,它里面存放的是令牌,令牌会以固定速率生成并放入到桶内,当桶满了,多余的令牌会被直接丢弃,当请求过来的时候,需要去令牌桶内拿令牌,拿到令牌才能够执行该请求,如果桶内空了,那么这个时候过来的请求会被直接丢弃。

很明显,该算法既可以应对突发的大量请求,也可以相对平稳的处理请求(固定速率生成),同时也没有什么所谓的边界突刺问题,这种算法是目前使用较为广泛的限流算法。

浙公网安备 33010602011771号