今天观看QCon大会讲述了阿里线上管控体系,其中主要使用了令牌桶算法来实现限流的目的。表示很是好奇,故此学习一下什么是令牌桶算法。算法
1. 简介api
令牌桶算法最初来源于计算机网络。在网络传输数据时,为了防止网络拥塞,需限制流出网络的流量,使流量以比较均匀的速度向外发送。令牌桶算法就实现了这个功能,可控制发送到网络上数据的数目,并容许突发数据的发送。缓存
令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型状况下,令牌桶算法用来控制发送到网络上的数据的数目,并容许突发数据的发送。网络
大小固定的令牌桶可自行以恒定的速率源源不断地产生令牌。若是令牌不被消耗,或者被消耗的速度小于产生的速度,令牌就会不断地增多,直到把桶填满。后面再产生的令牌就会从桶中溢出。最后桶中能够保存的最大令牌数永远不会超过桶的大小。学习
传送到令牌桶的数据包须要消耗令牌。不一样大小的数据包,消耗的令牌数量不同。优化
令牌桶这种控制机制基于令牌桶中是否存在令牌来指示何时能够发送流量。令牌桶中的每个令牌都表明一个字节。若是令牌桶中存在令牌,则容许发送流量;而若是令牌桶中不存在令牌,则不容许发送流量。所以,若是突发门限被合理地配置而且令牌桶中有足够的令牌,那么流量就能够以峰值速率发送。计算机网络
2.算法过程设计
算法描述:队列
假如用户配置的平均发送速率为r,则每隔1/r秒一个令牌被加入到桶中(每秒会有r个令牌放入桶中);it
假设桶中最多能够存放b个令牌。若是令牌到达时令牌桶已经满了,那么这个令牌会被丢弃;
当一个n个字节的数据包到达时,就从令牌桶中删除n个令牌(不一样大小的数据包,消耗的令牌数量不同),而且数据包被发送到网络;
若是令牌桶中少于n个令牌,那么不会删除令牌,而且认为这个数据包在流量限制以外(n个字节,须要n个令牌。该数据包将被缓存或丢弃);
算法容许最长b个字节的突发,但从长期运行结果看,数据包的速率被限制成常量r。对于在流量限制外的数据包能够以不一样的方式处理:(1)它们能够被丢弃;(2)它们能够排放在队列中以便当令牌桶中累积了足够多的令牌时再传输;(3)它们能够继续发送,但须要作特殊标记,网络过载的时候将这些特殊标记的包丢弃。
注意:
令牌桶算法不能与另一种常见算法漏桶算法相混淆。这两种算法的主要区别在于漏桶算法可以强行限制数据的传输速率,而令牌桶算法在可以限制数据的平均传输速率外,还容许某种程度的突发传输。在令牌桶算法中,只要令牌桶中存在令牌,那么就容许突发地传输数据直到达到用户配置的门限,所以它适合于具备突发特性的流量。
3.Java实现
咱们可使用Guava 的 RateLimiter 来实现基于令牌桶的流控,RateLimiter 令牌桶算法是单桶实现。RateLimiter 对简单的令牌桶算法作了一些工程上的优化,具体的实现是 SmoothBursty。须要注意的是,RateLimiter 的另外一个实现SmoothWarmingUp,就不是令牌桶了,而是漏桶算法。也许是出于简单起见,RateLimiter 中的时间窗口能且仅能为 1s。
SmoothBursty 有一个能够放 N 个时间窗口产生的令牌的桶,系统空闲的时候令牌就一直攒着,最好状况下能够扛 N 倍于限流值的高峰而不影响后续请求。RateLimite容许某次请求拿走超出剩余令牌数的令牌,可是下一次请求将为此付出代价,一直等到令牌亏空补上,而且桶中有足够本次请求使用的令牌为止。当某次请求不能获得所须要的令牌时,这时涉及到一个权衡,是让前一次请求干等到令牌够用才走掉呢,仍是让它先走掉后面的请求等一等呢?Guava 的设计者选择的是后者,先把眼前的活干了,后面的过后面再说。