一、漏桶算法
漏桶算法,又称leaky bucket。为了理解漏桶算法,我们看一下对于该算法的示意图:
从图中我们可以看到,整个算法其实十分简单。首先,我们有一个固定容量的桶,有水流进来,也有水流出去。对于流进来的水来说,我们无法预计一共有多少水会流进来,也无法预计水流的速度。但是对于流出去的水来说,这个桶可以固定水流出的速率。而且,当桶满了之后,多余的水将会溢出。
我们将算法中的水换成实际应用中的请求,我们可以看到漏桶算法天生就限制了请求的速度。当使用了漏桶算法,我们可以保证接口会以一个常速速率来处理请求。所以漏桶算法天生不会出现临界问题。
漏桶算法可以粗略的认为就是注水漏水过程,往桶中以一定速率流出水,以任意速率流入水,当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。
二、漏桶算法小栗子
来看个小栗子:
public class LeakyBucket { public long timeStamp = System.currentTimeMillis(); // 当前时间 public long capacity; // 桶的容量 public long rate; // 水漏出的速度 public long water; // 当前水量(当前累积请求数) public boolean grant() { long now = System.currentTimeMillis();
//(now - timeStamp)* rate // 漏水量
// 先执行漏水,计算剩余水量 water = Math.max(0, water - (now - timeStamp) * rate); timeStamp = now; if ((water + 1) < capacity) { // 尝试加水,并且水还未满 water += 1; return true; } else { // 水满,拒绝加水 return false; } } }
说明:
(1)未满加水:通过代码 water +=1进行不停加水的动作。
(2)漏水:通过时间差来计算漏水量。
(3)剩余水量:总水量-漏水量。
三、算法对比
3.1 计数器 VS 滑动窗口:
计数器算法是最简单的算法,可以看成是滑动窗口的低精度实现。滑动窗口由于需要存储多份的计数器(每一个格子存一份),所以滑动窗口在实现上需要更多的存储空间。也就是说,如果滑动窗口的精度越高,需要的存储空间就越大。
3.2漏桶算法 VS 令牌桶算法:
漏桶算法和令牌桶算法最明显的区别是令牌桶算法允许流量一定程度的突发。因为默认的令牌桶算法,取走token是不需要耗费时间的,也就是说,假设桶内有100个token时,那么可以瞬间允许100个请求通过。
令牌桶算法由于实现简单,且允许某些流量的突发,对用户友好,所以被业界采用地较多。当然我们需要具体情况具体分析,只有最合适的算法,没有最优的算法。
总结:
(1)常用限流算法:滑动窗口算法(也叫滑动时间窗口算法)、令牌桶算法、漏桶算法。
(2)Sentinel限流算法
- 流控效果就是限流算法的配置。
- 快速失败 – 滑动时间窗口算法;
- Warm Up – 令牌桶算法;
- 排队等待 - 漏桶算法。
(3)流量控制组件:Hystrix、Sentinel
SentinelVS Hystrix:
还有一个框架是resilience4j:
(now - timeStamp) * rate)