说到限流,我们最多想到的是google公司的guava的RateLimit限流工具类。令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。其实对于限制接口流量不是特别好
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
以下是根据令牌桶算法改后的用法:如有问题,请多多批评!!!
代码地址:https://gitee.com/xiaobaer/Svimer/tree/master/svimer-core
首先确认的是,令牌桶里没有令牌,只是令牌信号量。异常令牌桶里才有令牌,令牌存放接口信息。
CirculateNoTokenBucket可以在调用接口前限制流量,还可以在调用接口后根据异常令牌监控接口使用情况。
创建一个固定容量及固定令牌信号量的容器CirculateNoTokenBucket circulateNoTokenBucket = CirculateNoTokenBucket.newBuilder().tokenBucketSize(15).build();
获取令牌桶空的信号量circulateNoTokenBucket.getTokenQueueRemainingCapacity()
获取有异常的令牌数量circulateNoTokenBucket.getAbnormalTokensSize()
输出异常令牌信息circulateNoTokenBucket.toString()
代码:
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.svimer.core.token.CirculateNoTokenBucket;
import com.svimer.core.token.Token;
public class CirculateNoTokenBucketTest {
public static void main(String[] args) throws InterruptedException {
CirculateNoTokenBucket circulateNoTokenBucket = CirculateNoTokenBucket.newBuilder().tokenBucketSize(15).build();
int size = 4;
ExecutorService pool = Executors.newFixedThreadPool(size);
while (true) {
TimeUnit.MILLISECONDS.sleep(500);
pool.execute(new Task(circulateNoTokenBucket));
}
}
static class Task implements Runnable {
private CirculateNoTokenBucket circulateNoTokenBucket;
public Task(CirculateNoTokenBucket circulateNoTokenBucket) {
this.circulateNoTokenBucket = circulateNoTokenBucket;
}
@Override
public void run() {
boolean tokens = circulateNoTokenBucket.getTokens(1);
if (tokens) {
try {
long startTime = System.currentTimeMillis(); // 获取出来的是当前时间的毫秒值
// 业务处理耗时
Random r = new Random();
TimeUnit.MILLISECONDS.sleep(r.nextInt(1000));
long endTime = System.currentTimeMillis(); // 获取出来的是当前时间的毫秒值
// 毫秒
long threshold = 500l;
long timeDifference = endTime - startTime;
if (timeDifference > threshold) {
Token token = new Token();
token.setEndTime(endTime);
token.setStartTime(startTime);
token.setTimeDifference(timeDifference);
token.setToken("abc");
token.setUrl("action地址");
circulateNoTokenBucket.addAbnormalToken(token);
System.out.println(circulateNoTokenBucket.getTokenQueueRemainingCapacity());
System.out.println(circulateNoTokenBucket.getAbnormalTokensSize());
System.out.println(circulateNoTokenBucket.toString());
} else {
circulateNoTokenBucket.addTokens(1);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println("token rejuect=========Execute ThreadName=" + Thread.currentThread().getName());
}
}
}