說到限流,我們最多想到的是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());
}
}
}