令牌桶:
① 用来控制发送到网络上的数据的数目,并允许突发数据的发送。
② 原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
漏桶:
①它的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。
②如果漏桶(包缓存)溢出,那么数据包会被丢弃。
③ 把请求比作是水,水来了都先放进桶里,并以限定的速度出水,当水来得过猛而出水不够快时就会导致水直接溢出,即拒绝服务。
两桶对比:都是流量整形(Traffic Shaping)或速率限制(Rate Limiting)。
1. 漏桶是出,令牌是进
2. 令牌是允许伸缩
案例:Google的Guava包中的RateLimiter类就是令牌桶算法的解决方案。
总结:
需要注意的是,在某些情况下,漏桶算法不能够有效地使用网络资源,因为漏桶的漏出速率是固定的,所以即使网络中没有发生拥塞,漏桶算法也不能使某一个单独的数据流达到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。而令牌桶算法则能够满足这些具有突发特性的流量。
算法实现:
1.Leaky Bucket:设置一个很小的流量请求上限,当流量达到了这个上限的时候就将其丢弃,即拒绝服务。当桶内有了新的空间后漏桶便可以再次接收新的请求。
方法:采用队列实现请求的(FIFO先进先出)。
优点:很小的内存做到为每个用户限流。
缺点:桶满了后,新的请求会被丢弃。
2.Fixed Window(固定窗口):设置一个时间段内(窗口)接收的请求数,超过的这个请求数的请求会被丢弃。
优点:和漏桶相比,能够让使得请求被处理到的概率更大了,就像12306的分批放票策略,“看起来”更公平了。
缺点:窗口一般会很小,而初始的流量一般都会远远大于窗口大小,所以在窗口的起始时间,最差的情况也可能会带来2倍的流量,从而导致很多消费者被搁置,会造成惊群效应。
3.Sliding Log(滑动日志):滑动日志算法,单位时间段内,利用记录下来的每个用户的请求时间,及其请求数。当新的一个请求进来后,先把该请求与当前请求日志信息进行对比,如果是新用户,就立即响应处理,否则再根据其请求数是否在窗口期超出预设的请求上限,决定是否处理该请求。
优点:避免了窗口算法在窗口边界可能出现的两倍流量问题(比如用户重复提交请求),即避免了用户的惊群效应。
缺点:保存大量日志,且由于完成请求前要比对用户请求数,故在分布式系统下操作难度大?
4.Sliding Window(滑动窗口):滑动窗口算法,结合了固定窗口算法的低开销和滑动日志算法能够解决的边界情况。
实现策略:a.为“每个”窗口设定请求数;b.结合上一个窗口的请求量和这个窗口已经经过的时间来计算上限,以此平滑请求峰值
案例:
举例来说,限流的上限是每分钟 10 个请求,窗口大小为 1 分钟,上一个 窗口中总共处理了 6 个请求。现在假设这个新的窗口已经经过了 20 秒,那么 到目前为止允许的请求上限就是 10 - 6 * (1 - 20 / 60) = 8
只有优点:
性能好、避免了漏桶算法带来的饥饿问题(后来的请求被拒绝服务)、避免了固定窗口算法的请求量突增的问题;
分布式实现:
难点在于限流上限都是针对全站的流量设置的,那么每个节点该如何协调各自处理的量呢?