一、计数器算法
计数器算法,是指在指定的时间周期内累加访问次数,达到设定的阈值时,触发限流策略。下一个时间周期进行访问时,访问次数清零。
此算法无论在单机还是分布式环境下时间都非常简单,使用Redis的incr原子自增性,再结合key的过期时间即可轻松实现。
从上图我们看到,设置一分钟的阈值是100,在0:00到1:00内,只在0:50有60个请求,而在1:00到2:00之间,只有在1:10有60个请求,虽然在两个一分钟内,都没超过100个请求,但是在0:50到1:10这20秒内,却有120个请求,虽然在每个周期内,都没超过阈值,但是在这20秒内,已经远远超过了我们原来设置的1分钟内100个请求的阈值。
二、滑动时间窗口算法
为了解决计数器算法的临界值的问题,发明了滑动窗口算法。在TCP网络通信协议中,就采用滑动时间窗口算法来解决网络拥堵问题。
滑动窗口算法是将计数器算法中的实际周期切分成多个小的时间窗口,分别在小的时间窗口中记录访问次数,然后根据时间将窗口往前滑动并删除过期的小时间窗口。最终只需要统计滑动窗口范围内的小时间窗口的总的请求数即可。
在上图中,假设我们设置一分钟的请求阈值为100,我们将一分钟拆分成4个小时间窗口,这样,每个小的时间窗口只能处理25个请求,我们用虚线方格表示滑动时间窗口,当前窗口的大小是2,也就是窗口内最多能处理50个请求。随着时间的推移,滑动时间窗口也随着时间往前移动,比如上图开始时,窗口是0:00-0:30的这个范围,过了15秒后,窗口是0:15-0:45这个范围,窗口中的请求重新清零,这样就很好的解决了计数器算法的临界值问题。
在滑动时间窗口算法中,我们的小窗口划分的越多,滑动窗口的滚动就越平滑,限流的统计就越精准。
三、漏桶限流算法
漏桶算法的原理就像他的名字一样,我们维护一个漏斗,它有恒定的流出速度,不管水流流入的速度有多快,漏斗出水的速度始终保持不变,类似于消息中间件,不管消息的生产者请求量有多大,消息的处理能力取决于消费者。
漏桶的容量 = 漏桶的流出速度 * 可接受的等待时长。在这个容量内的请求可以排队等待系统的处理,超过这个容量的请求,才会被抛弃。
在漏桶限流算法中,存在下面几种情况:
- 当请求速度大于漏桶的流出速度时,也就是请求量大于当前服务器所能处理的最大极限时,触发限流策略。
- 请求速度小于或等于漏桶的流出速度时,也就是服务的处理能力大于或等于请求量时,正常执行。
漏桶算法有一个缺点:当系统在短时间内有突发的大流量时,漏桶算法处理不了。
四、令牌桶限流算法
令牌桶算法,是增加一个大小固定的容器,也就是令牌桶,系统以恒定的速率向令牌桶中放入令牌,如果有客户端来请求,先需要从令牌桶中拿一个令牌,拿到令牌,才有资格访问系统,这时令牌中少一个令牌。当令牌桶满的时候,再向令牌桶生成令牌时,令牌会被抛弃。
在令牌桶算法中,存在以下几种情况:
- 请求速度大于令牌的生成速度:那么令牌桶中的令牌会被取完,后续再进来的请求,由于拿不到令牌,会被限流。
- 请求速度等于令牌的生成速度:那么此时系统处于平稳状态。
- 请求速度小于令牌的生成速度:那么此时系统的访问量远远低于系统的并发能力,请求可以被正常处理。
令牌桶算法,由于有一个桶的存在,可以处理短时间大流量的场景。这是令牌桶和漏桶的一个区别。