一、什么是限流
限流是指在高并发、大流量请求的情况下,限制新的流量对系统的访问,从而保证系统服务的安全性。
限流可以应对:热点业务带来的突发请求;调用方bug导致的突发请求;恶意攻击请求
二、为什么要分布式限流
当应用为单点应用时,只要应用进行了限流,那么应用所依赖的各种服务也得到了保护。但线上的业务出于各种原因考虑,多是分布式系统,单点的限流仅能保护自身节点,但无法保护应用依赖的各种服务,并且在进行节点扩容缩容时也无法整个服务的请求限制。而如果实现了分布式限流,那么就可以方便的控制整个服务集群的请求限制,,且由于整个集群的请求数量受到了限制,因此服务依赖的各种资源也得到了限流的保护。
三、常见的限流算法
固定窗口计数器法
该算法规定我们单位时间处理的请求数量。比如规定一个接口一分钟是能访问十次的话,使用固定窗口计数算法可以这样实现:给定一个变量counter来记录处理的请求数量,当一分钟内处理一个请求后counter+1,一分钟内如果counter大于100,后续所有的请求都会被拒绝,等到一分钟结束后,counter将回归成0,重新计数。(只要过了一个周期counter就会重新计数)
这种限流算法无法保证限流速率,因而无法保证突然激增的流量。比如我们限制一个接口一分钟只能访问10次,前半分钟一个请求没有,后半分钟接收了10个请求
滑动窗口计数器算法
该算法是上一个固定窗口计数算法的升级版,滑动窗口计数器算法相比于固定窗口计数器算法的优化在于:他把时间以一定比例分成片。例如限流每分钟处理60个请求,我们可以把1分钟分成60个窗口。每个一秒移动一次,每个窗口一秒只能处理不大于60(请求书) / 60(窗口数)的请求,如果当前窗口的计数总和超过了限制数量的话就不在处理其他请求。
很显然:滑动窗口格子划分的越多,滑动窗口滚动越平滑,限流的统计就会越精确。
漏桶算法
我们可以把发送请求的动作比作注入到水桶中,处理请求的过程可以比喻为漏桶漏水。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶容量就丢弃,因为桶容量是不变的,保证了整体的速率。实现这个算法也很简单,准备一个队列保存请求,然后定期从队列中拿请求来实行
令牌桶算法
和漏桶算法一样,主角还是桶。不过现在桶里装的是令牌,请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃(删除)。根据限流大小,按一定速率往桶里添加令牌
四、各算法比较
算法 | 确定参数 | 空间复杂度 | 时间复杂度 | 限制突发流 | 平滑限流 | 分布式环境下实现难度 |
固定窗口 | 计数周期T、周期内最大访问数N | 低O(1)(记录周期内访问次数及周期开始时间) | 低O(1) | 否 | 否 | 低 |
滑动窗口 | 计数周期T、周期内最大访问数N | 高O(N)(记录每个周期中的访问数量) | 中O(N) | 是 | 滑动窗口格子分配越多,滑动窗口滚动越平滑 | 中 |
漏桶算法 | 漏桶流出速度r,漏桶容量N | 低O(1)(记录当前漏桶中的容量) | 高O(N) | 是 | 是 | 高 |
令牌桶算法 | 漏桶流出速度r,漏桶容量N | 低O(1)(记录当前桶中的令牌数) | 高O(N) | 是 | 是 | 高 |