Current limiting principle and actual combat
There are three algorithms for interface traffic limiting, namely, counter traffic limiting, leaky bucket algorithm and token bucket algorithm
Counter current limiting principle
Principle: Within a time window (interval), there is a limit on the number of requests that can be processed. The number of requests that exceed the limit is not processed.
Code implementation
@Slf4j
public class CountLimiter {
private static long startTime = System.currentTimeMillis();
// Time interval
private static long interval = 1000;
// The maximum number of requests processed within the interval
private static long maxCount = 2;
/ / counter
private static AtomicInteger accumulator = new AtomicInteger();
// Within 1 second, only 2 requests are allowed. If the time slice is checked, the initialization parameter enters a new time slice
private static long tryAcquire(long taskId, int turn){
long nowTime = System.currentTimeMillis();
If the number is less than or equal to the maximum number of allowed requests within a period of time, the number is returned
if (nowTime < startTime + interval){
int count = accumulator.incrementAndGet();
if (count <= maxCount){
return count;
}else {
return-count; }}else {
// Reset the counter and start time
synchronized (CountLimiter.class){
log.info("TaskId {}, turn{}..", taskId, turn);
if (nowTime > startTime + interval){
accumulator.set(0); startTime = nowTime; }}return 0; }}private ExecutorService pool = Executors.newFixedThreadPool(10);
@Test
public void testLimit(a){
AtomicInteger limited = new AtomicInteger(0);
final int threads = 2;
final int turns = 20;
CountDownLatch countDownLatch = new CountDownLatch(threads);
long start = System.currentTimeMillis();
for (int i = 0; i < threads; i++){ pool.submit(() -> {try {
for (int j = 0; j < turns; j++) {
long taskId = Thread.currentThread().getId();
long index = tryAcquire(taskId, j);
if (index <= 0){
limited.getAndIncrement();
}
Thread.sleep(200); }}catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
float time = (System.currentTimeMillis() - start) /1000F;
log.info("Limit times are:" + limited.get() + ", pass times are :"+(threads*turns - limited.get()));
log.info("The restricted proportion is:"+ (float)limited.get()/((float) threads*turns));
log.info("Running time:"+time); }}Copy the code
Leakage bucket current limiting principle and Java reference implementation
Basic principle of leakage bucket flow limiting
1) Water flows into the drain bucket at any rate through the water inlet (corresponding to client request). 2) The capacity of the leakage bucket is fixed, and so is the rate of discharge. 3) The leakage bucket capacity is unchanged. If the processing speed is too slow, the water in the bucket will exceed the capacity of the bucket, and the water flowing in the back will overflow, indicating that the request is rejected.
private static long lastOutTime = System.currentTimeMillis();
// The outflow rate is 2 per second
private static int rate = 2;
// The amount of water left
private static long water = 0;
/** * false: not restricted * true: restricted *@param taskId
* @param turns
* @return* /
public synchronized static boolean tryAcquire(long taskId, int turns){
long now = System.currentTimeMillis();
long pastTime = now - lastOutTime;
long outWater = pastTime * rate/ 1000;
water = water -outWater;
log.info("water {} pastTime {} outWater {}",water ,pastTime, outWater);
if (water < 0){
water = 0;
}
if (water <= 1){
lastOutTime = now;
water ++ ;
return false;
}else {
return true; }}Copy the code
Token bucket flow limiting principle and Java reference implementation
The general rules of token bucket flow limiting are as follows:
(1) The inlet puts the token into the bucket at a certain speed. (2) The capacity of token is fixed, but the speed of release is not fixed. As long as there are remaining tokens in the bucket, the application can be successful once the request comes, and then release. (3) If the token is issued slower than the request arrives, there are no tokens in the bucket and the request is rejected.
@Slf4j
public class TokenBucketLimiter {
// When the last token was issued
public long lastTime = System.currentTimeMillis();
// The capacity of a bucket
public int capacity = 2;
// Token generation speed per second
public int rate = 2;
// The number of current tokens
public int tokens;
// Return value description
/** * false: not restricted * true: restricted *@param taskId
* @param turns
* @return* /
public synchronized boolean tryAcquire(long taskId, int applyCount){
long now = System.currentTimeMillis();
// Time interval
long gap = now - lastTime;
// The current number of tokens
tokens = Math.min(capacity, (int)(tokens+gap*rate/1000));
log.info("tokens {} capacity {} gap {}",tokens ,capacity, gap);
if (tokens < applyCount){
log.info("The flow is restricted... {} ,applyCount:{}",taskId,applyCount);
return true;
}else {
tokens -= applyCount;
lastTime = now;
log.info("Remaining token.." + tokens);
return false; }}private ExecutorService pool = Executors.newFixedThreadPool(10);
@Test
public void testLimit(a){
AtomicInteger limited = new AtomicInteger(0);
final int threads = 2;
final int turns = 20;
CountDownLatch countDownLatch = new CountDownLatch(threads);
long start = System.currentTimeMillis();
for (int i = 0; i < threads; i++){ pool.submit(() -> {try {
for (int j = 0; j < turns; j++) {
long taskId = Thread.currentThread().getId();
boolean isLimited = tryAcquire(taskId, 1);
if (isLimited){
limited.getAndIncrement();
}
Thread.sleep(200); }}catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
float time = (System.currentTimeMillis() - start) /1000F;
log.info("Limit times are:" + limited.get() + ", pass times are :"+(threads*turns - limited.get()));
log.info("The restricted proportion is:"+ (float)limited.get()/((float) threads*turns));
log.info("Running time:"+time); }}Copy the code