1、场景
我们知道,硬件设备或是服务器之类的通信速率或是服务器的响应速率是有限制的,当瞬时大量通信量情况下需要对速率进行限制,否则可能会出现宕机等服务无法提供的故障。
两个比较常用的算法有令牌桶算法、漏桶算法,是目前最常用的流量限制的方法。
2、漏桶算法
如上图所示,我们假设系统是一个漏桶,当请求到达时,就是往漏桶里“加水”,而当请求被处理掉,就是水从漏桶的底部漏出。水漏出的速度是固定的,当“加水”太快,桶就会溢出,也就是“拒绝请求”。从而使得桶里的水的体积不可能超出桶的容量。
上面的分析可以看出,该算法存在三个变量:桶的容量capacity,水漏出的速度rate,以及当前的水量water。
算法伪代码如下:
long timeStamp=getNowTime();
int capacity; // 桶的容量
int rate ; //水漏出的速度
int water; //当前水量
bool grant() {
//先执行漏水,因为rate是固定的,所以可以认为“时间间隔*rate”即为漏出的水量
long now = getNowTime();
water = max(0, water- (now - timeStamp)*rate);
timeStamp = now;
if (water < capacity) { // 水还未满,加水
water ++;
return true;
} else {
return false;//水满,拒绝加水
}
}
3、令牌桶算法
令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。从原理上看,令牌桶算法和漏桶算法是相反的,一个“进水”,一个是“漏水”。
long timeStamp=getNowTime();
int capacity; // 桶的容量
int rate ; //令牌放入速度
int tokens; //当前水量
bool grant() {
//先执行添加令牌的操作
long now = getNowTime();
tokens = max(capacity, tokens+ (now - timeStamp)*rate);
timeStamp = now;
//令牌已用完,拒绝访问
if(tokens<1){
return false;
}else{//还有令牌,领取令牌
tokens--;
retun true;
}
}
4、两者区别
令牌桶里面装载的是令牌,然后让令牌去关联到数据发送,常规漏桶里面装载的是数据,令牌桶允许用户的正常的持续突发量(Bc),就是一次就将桶里的令牌全部用尽的方式来支持续突发,而常规的漏桶则不允许用户任何突发行。