原理介绍
Leaky Bucket 与 Token Bucket 算法
实现方式
1. 简单实现,无burst控制
public enum APIRateLimiter {
long minIntervalMilis;
private AtomicLong lastRequestTime = new AtomicLong(0);
public boolean acquire() {
int maxAttempts = 5;
while (maxAttempts-- > 0) {
long lastRequestMils = lastRequestTime.longValue();
long awaitTime = minIntervalMilis - (System.currentTimeMillis() - lastRequestMils);
if (awaitTime > 0) {
try {
//Log.out("sleep %s mili seconds to aquire lease ...", awaitTime);
Thread.sleep(awaitTime);
} catch (InterruptedException e) {
}
} else {
if (lastRequestTime.compareAndSet(lastRequestMils, System.currentTimeMillis())) {
return true;
}
}
}
return false;
}
}
2. 有burst控制
Google Guava中的RateLimiter,实际上就实现了Token Bucket的算法。Google搜索看到有些开源项目的issues,要把自己写的Limiter换成了它。
它支持两种获取permits接口,一种是如果拿不到立刻返回false,一种会阻塞等待一段时间看能不能拿到。
Leacky Bucket算法默认一开始水桶是空的,可以立即就接收最多burst的请求,而Token Bucket就要设置初始Token的数量。
RateLimiter有两个子类,一个是WarmingUp,一个是Bursty。
- WarmingUp,burst = warmUp时间/固定token添加间隔,初始token数量 = burst,有算法保证系统总是相对平滑。
- Bursty, burst = rate或另外的参数设置,初始token数量 = 0 ,当系统冷了一段时间,支持突发到burst。
Guava以micros为时间单位,计算token的变化。
参考文章
https://github.com/springside/springside4/wiki/Rate-Limiter
http://xiaobaoqiu.github.io/blog/2015/07/02/ratelimiter/