From Token Bucket to Leaky Bucket: Exploring Two Classical Algorithms for Interface Current Limiting

Table of contents

1. Token Bucket Algorithm

                  1.1 The principle of the leaky bucket algorithm:

1.2 The role of the leaky bucket algorithm:

1.3 Realize the use case

2. Leaky Bucket Algorithm

2.1 The principle of the token bucket algorithm:

2.2 The role of the token bucket algorithm:

2.3 Realize the use case


1. Token Bucket Algorithm

1.1 The principle of the leaky bucket algorithm:

  • Leaky bucket: Like a virtual leaky bucket, it has a fixed capacity and can store a certain number of requests.
  • Requests enter the leaky bucket: When a request arrives, it will be put into the leaky bucket, occupying a certain capacity.
  • Processing requests: The system processes requests in the leaky bucket at a constant rate, independent of the rate at which requests arrive.
  • Requests leave the bucket: After each request is processed, it is released from the bucket at a constant rate, just like water flowing out of the bucket.

1.2 The role of the leaky bucket algorithm:

  • Smooth traffic: The leaky bucket algorithm can smoothly control the traffic output by the system, so that the system can provide services stably and prevent system crash or performance degradation caused by a large number of sudden requests.
  • Control the output rate: By setting a constant processing rate, the leaky bucket algorithm can control the output speed of the system to provide external services, and protect the stability and availability of the system.
  • Protection of system resources: The leaky bucket algorithm can limit the consumption of resources by the system and prevent malicious requests or overloads under abnormal conditions from causing damage to the system.
  • Balance system load: The leaky bucket algorithm can disperse the pressure of requests, balance the load of the system, and avoid excessive utilization of some resources and cause other resources to fail to work normally.

1.3 Realize the use case

  •  logic class
package com.jmh.demo03.current.utils;

public class RateLimiter {
    private static RateLimiter instance;
    private final int maxTokens;
    private final int tokensPerSecond;
    private int availableTokens;
    private long lastRefillTimestamp;

    private RateLimiter(int maxTokens, int tokensPerSecond) {
        this.maxTokens = maxTokens;
        this.tokensPerSecond = tokensPerSecond;
        this.availableTokens = maxTokens;
        this.lastRefillTimestamp = System.currentTimeMillis();
    }

    public static synchronized RateLimiter getInstance(int maxTokens, int tokensPerSecond) {
        if (instance == null) {
            instance = new RateLimiter(maxTokens-1, tokensPerSecond);
        }
        return instance;
    }

    public synchronized boolean isAllowed() {
        refillTokens();

        if (availableTokens > 0) {
            availableTokens--;
            return true;
        }

        return false;
    }

    private void refillTokens() {
        long currentTime = System.currentTimeMillis();
        long elapsedTime = currentTime - lastRefillTimestamp;
        long refillInterval = 1000 / tokensPerSecond;
        int tokensToAdd = (int)(elapsedTime / refillInterval);

        if (tokensToAdd > 0) {
            lastRefillTimestamp = currentTime;

            if (availableTokens + tokensToAdd <= maxTokens) {
                availableTokens += tokensToAdd;
            } else {
                availableTokens = maxTokens;
            }
        }
    }
}
  •  call class
package com.jmh.demo03.current.controller;

import com.jmh.demo03.current.utils.LeakyBucketRateLimiter;
import com.jmh.demo03.current.utils.RateLimiter;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author 蒋明辉
 * @data 2023/8/8 16:16
 */
@RequestMapping("/current")
@RestController
public class currentController {

    //令牌桶
    //参数:容量(10)和令牌产生速率(10)。
    //工作原理:在令牌桶中以固定的速率生成令牌,每个令牌代表一个请求。仅当有令牌可用时,才能进行接口调用。
    //效果:在开始时,令牌桶中有 10 个令牌。每秒钟会生成 10 个新令牌,所以在第一秒内您可以连续调用接口 10 次。如果超过了 10 次调用,则需要等待后续的秒数以获取新的令牌。
    private final RateLimiter rateLimiter = RateLimiter.getInstance(10, 1);

    /**
     * 令牌桶限流
     *
     * @return 限流结果
     */
    @PostMapping("demo01")
    @SneakyThrows
    public boolean demo01() {

        return rateLimiter.isAllowed();
    }
}

2. Leaky Bucket Algorithm

2.1 The principle of the token bucket algorithm:

  • Token Generation: Tokens are generated at a fixed rate in the token bucket, such as a certain number of tokens per second.
  • Token consumption: When a request arrives, a token needs to be obtained from the token bucket. If there is an available token in the bucket, it will be issued to the request and processed; if there are not enough tokens in the bucket, then Deny the request.
  • Token storage: The token bucket has a maximum capacity, which is the maximum number of tokens that can be stored in the token bucket. When the token generation rate exceeds the token consumption rate, excess tokens will be stored in the bucket, but will not exceed the maximum capacity.

2.2 The role of the token bucket algorithm:

  • Smooth flow: The token bucket algorithm can smoothly control the flow of requests, so that the system can process requests at a stable rate, preventing a large number of sudden requests from causing system crashes or performance degradation.
  • Control access rate: By limiting the rate of token generation, the token bucket algorithm can control the access rate of the system's external services and protect the stability and availability of the system.
  • Flexible adaptation to burst traffic: The token bucket algorithm allows a large number of tokens to be generated in a short period of time to handle short-term burst traffic without causing long-term performance problems.
  • Fairness: The token bucket algorithm guarantees the fairness of requests, and each request is equal when obtaining tokens, without privileges or priorities.

2.3 Realize the use case

  • logic class
package com.jmh.demo03.current.utils;

import java.time.Duration;
import java.time.Instant;

public class LeakyBucketRateLimiter {
    private final int capacity; // 漏斗容量
    private final int rate; // 每秒流出的速率
    private int water; // 当前水量
    private Instant lastRequestTime; // 上次请求时间

    public LeakyBucketRateLimiter(int capacity, int rate) {
        this.capacity = capacity;
        this.rate = rate;
        this.water = 0;
        this.lastRequestTime = Instant.now();
    }

    public synchronized boolean isAllowed() {
        Instant now = Instant.now();
        Duration elapsedTime = Duration.between(lastRequestTime, now);
        lastRequestTime = now;

        int elapsedSeconds = (int) elapsedTime.getSeconds();
        water = Math.max(0, water - elapsedSeconds * rate);

        if (water < capacity) {
            water++;
            return true; // 允许请求通过
        }

        return false; // 限制请求访问
    }
}
  • call class
package com.jmh.demo03.current.controller;

import com.jmh.demo03.current.utils.LeakyBucketRateLimiter;
import com.jmh.demo03.current.utils.RateLimiter;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author 蒋明辉
 * @data 2023/8/8 16:16
 */
@RequestMapping("/current")
@RestController
public class currentController {

    //漏桶
    //参数:容量(10)和流出速率(10)。
    //工作原理:漏桶按照固定的速率流出请求,不管请求是否连续到达。当漏桶存储的请求数量超过容量时,多余的请求将被丢弃。
    //效果:在开始时,漏桶为空,可以立即调用接口。但是,一旦第一秒内的调用超过了容量(10 次),后续的请求将被漏桶丢弃,直到漏桶重新流出新的请求(每秒 10 次)。
    private final LeakyBucketRateLimiter limiter = new LeakyBucketRateLimiter(10, 10);

    /**
     * 漏桶限流
     * @return 限流结果
     */
    @PostMapping("demo02")
    @SneakyThrows
    public boolean demo02() {

        return limiter.isAllowed();
    }

}

Guess you like

Origin blog.csdn.net/m0_63300795/article/details/132180755