《飞鸟集》
泰戈尔
樵夫的斧头,问树要斧柄。
树便给了他。
简介
建立面对超额流量自我保护的机制,这个机制就是流量控制。令牌桶模式与漏桶一样都是基于缓冲区的限流算法。令牌代表流量是否允许通过的凭据,以固定的速率添加到桶中。当一个流量是否符合定义的限制时,会先检查桶中是否包含足够的令牌。如果是,就消费特定数量的令牌,流量被传递;否则就对流量进行降级处理。
Java实现
public class TokenBucketRateLimiter {
private final long capacity;
private final long ratesPerSecond;
private long availableTokens;
private long lastRefilledTime;
public TokenBucketRateLimiter(long ratesPerSecond) {
this(100, ratesPerSecond);
}
public TokenBucketRateLimiter(long capacity, long ratesPerSecond) {
this.capacity = capacity;
this.ratesPerSecond = ratesPerSecond;
}
public synchronized boolean tryConsume() {
refillTokens();
if (availableTokens > 0) {
availableTokens--;
return true;
} else return false;
}
private void refillTokens() {
long now = System.currentTimeMillis();
if (lastRefilledTime == 0) {
availableTokens = ratesPerSecond;
lastRefilledTime = now;
} else if (now > lastRefilledTime) {
long elapsedMillis = now - lastRefilledTime;
long tokensToFill = elapsedMillis / 1000 * ratesPerSecond;
availableTokens = Math.min(capacity, availableTokens + tokensToFill);
lastRefilledTime = now;
}
}
}
每次请求时(这里使用Java中的线程执行一个任务表示)调用tryConsume确定是否符合流量控制的规则。
测试代码如下:
static final ThreadPoolExecutor exec = new ThreadPoolExecutor(16, 16, 0,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(84),
new ThreadPoolExecutor.AbortPolicy());
static int num = 0;
public static void main(String[] args) throws InterruptedException {
TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(100, 2);
while (true){
for (int i = 0; i < 100; i++) {
if (limiter.tryConsume()) {
exec.execute(() -> System.out.println(++num));
}
}
TimeUnit.SECONDS.sleep(1);
}
}
测试代码中我们将流量控制速率设置为了2QPS,从方法输出结果可以看出每秒打印num的2个连续的递增结果。