令牌桶
限制的是平均流入速率。令牌桶算法在突发情况下,处理速率可以超过限制。算是漏桶的改进版,能够防止一定程度的流量突发。突发流量大于生成速率但是小于桶的容量,也是能够接受的。
原理:
- 令牌桶会存放一定数量的令牌(令牌桶装的是令牌,不是流量),一个请求通过会消耗一个令牌。桶中没有令牌时,就无法通过任何数据。
- 为了接口保证能通过数据,就需要往桶里增加令牌。增加令牌的速度决定了流量通过的速度,这一点和漏桶类似。
- 当有流量进入令牌桶时,需要拥有对应数量的令牌才能通过,如果没有,该请求就会被拒绝。
- 由于令牌桶有存量,可以防止一定程度的流量突发,只要平均速率在合理控制范围内就可以接受。
实现
参数
- 令牌产生速率
- 更新时间(用于计算令牌产生数量)
- 桶容量
- 当前令牌数量
// 令牌生速率
private int speed = 1;
// 更新时间
private long updateTime;
// 桶容量
private int capacity = 100;
// 当前令牌数量
public int num;
方法
当流量进入时,先更新当前时间的令牌数量。如果令牌数量足够,就消耗令牌,通过。
public String filter(int permit) {
/*先结算令牌数量*/
long now = System.currentTimeMillis();
//上限为桶容量,超过就丢弃
long time = (now -this.updateTime) / 1000;
this.num = Math.toIntExact(Math.min(capacity,this.num + time * speed));
this.updateTime = now;
String message = "当前令牌数:"+this.num+",需要令牌数"+permit;
if(this.num < permit) {
String error = message+",请求拒绝================";
System.out.println(message);
return error;
}
else{
System.out.println(message);
this.num =this.num - permit;
return message;
}
与漏桶的比较
存放对象
- 漏桶存放的是请求量,当请求速率大于通过速率,多余的请求就会存放到漏桶中。
- 令牌桶存放的是令牌量,生成的令牌都会放入令牌桶中被消耗。如果令牌的数量已满,就会丢弃多余的令牌。
限制方法
- 以流出速率限制流量。被限制的流量会保存在漏桶中,以便平缓通过。桶中存满后多余流量会被拒绝。
- 以令牌产生速率限制流量。流量通过时需要消耗对应数量的令牌才能通过,那么令牌产生的速率小于流量通过的速率,就能限制流量。多余的流量(没有令牌可以消耗)会被缓存或者丢弃。