限流
从是否对限流数据进行统一聚合,可以大致划分为本地(单实例)限流和分布式(中心化)限流。
固定窗口(计数器)
在单位时间内进行计数,如果请求数大于设置的最大值,则进行拒绝;如果过了单位时间,则重新进行计数。
- 优势:简单易实现。
- 劣势:突发流量会出现毛刺现象,限流不准确。
由于是对整一秒进行计数,假设我们限制一秒内最多10条请求。在第一秒的后0.5秒出现了10条,在第二秒的前0.5秒出现了10条。这样由于它只对整一秒进行计数,因此这样是不会触发限制。而实际上在一秒内触发了20条请求,是限流不准确的情况。
滑动窗口
在滑动窗口中根据统计周期和窗口的大小开始滑动。窗口越大统计精准度越低,但并发性能好;窗口越小,统计精准度越高,并发性能随之降低。
- 优势:将固定时间段分块,时间比”计数器”复杂,适用于稍微精准的场景。较好地解决了固定窗口存在的边界(毛刺问题)问题。
- 劣势:时间区间精度越高,算法所需的空间容量就越大。不能彻底解决“计数器”存在的边界问题。
漏桶
使用一个有最大容量的队列来作为漏桶。请求进入队列,队列按照固定速率出队,如果队列已满则丢弃请求。
漏桶算法能够在一定程度上解决“计数器”存在的边界问题,但是任何请求的出入都会有延迟和资源的消耗。
- 优势:限流稳定。
- 劣势:即便服务器在没有负载的情况下,每个进来的请求在响应前也会存在一段延迟。
令牌桶
令牌以固定速率生成。生成的令牌放入令牌桶中存放,如果令牌桶满了则多余的令牌会直接丢弃,当请求到达时,会尝试从令牌桶中取令牌,取到了令牌的请求可以执行。如果桶空了,那么尝试取令牌的请求会被直接丢弃。
-
优势:令牌桶算法既能够将所有的请求平均分布到时间区间内,又能接受服务器能够承受范围内的突发请求,因此是目前使用较为广泛的一种限流算法。
-
劣势:需要提前设置阈值;结构复杂;频繁获取令牌压力大;令牌获取异常会导致流量被误限。
总结
综上,我们可以发现“固定窗口”和“滑动窗口”这两种限流方式,其实都是被动地扫描。用户把请求先打进来,服务端再根据进来的请求进行处理,看看到底能放行多少请求进去。
而对于“漏桶”和“令牌桶”则是主动地控制流量,通过控制流量的进入和流出,达到限流的目的。请求主动地来申请通过的权限,如果服务器不给权限,则无法通过。
这两种的对比其实就像 select 和 epoll 系统调用的对比,select 是被动的,使用轮询去查看;epoll 则是主动的,基于事件的,不关注对方的状态,只关注自己感兴趣的事件。