Home  >  Article  >  Java  >  How to use springboot to integrate RateLimiter current limiting

How to use springboot to integrate RateLimiter current limiting

WBOY
WBOYforward
2023-05-12 10:40:061661browse

RateLimiter token bucket schematic

How to use springboot to integrate RateLimiter current limiting

  • As time passes, the system will follow a constant 1/QPS time interval (if QPS=100, Then the interval is 10ms) Add Token to the bucket (imagine the opposite of leakage, there is a faucet constantly adding water), if the bucket is full, no more will be added. When a new request comes, each will take away a Token. If If there is no token available, it will block or deny service.

  • Another benefit of the token bucket is that it can easily change the speed. Once the speed needs to be increased, increase it as needed and put it in the bucket. The rate of tokens. Generally, a certain number of tokens will be added to the bucket regularly (such as 100 milliseconds). Some variant algorithms calculate the number of tokens that should be added in real time.

Token bucket is a commonly used traffic control technology. The token bucket itself has no discarding and priority policies.

Principle

1. Tokens are put into the bucket at a certain rate.

2. Each token allows the source to send a certain number of bits.

3. To send a packet, the traffic conditioner removes a number of tokens from the bucket equal to the packet size.

4. If there are not enough tokens to send a packet, the packet waits until there are enough tokens (in the case of a shaper) or the packet is dropped, possibly marked with a lower DSCP (in the case of a policyr).

5. Buckets have a specific capacity. If the bucket is full, newly added tokens will be discarded. Therefore, the maximum amount of burst data a source can send onto the network at any time is proportional to the bucket size. The token bucket allows bursts, but cannot exceed the limit.

Method summary

Modifiers and types Method and description
double acquire() Gets a permission from RateLimiter. This method will be blocked until the request is obtained.
double acquire(int permits) Obtains the specified number of permits from RateLimiter. This method will be blocked until the request is obtained
static RateLimiter create(double permitsPerSecond) Creates a RateLimiter based on the specified stable throughput rate, where the throughput rate refers to the number of permits per second (usually QPS, how many queries per second)
static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) Create a RateLimiter based on the specified stable throughput rate and warm-up period. The throughput rate here refers to how much per second The number of licenses (usually refers to QPS, how many requests per second). During this warm-up period, the number of licenses allocated by RateLimiter per second will grow steadily until it reaches its maximum rate at the end of the warm-up period. (As long as there are enough requests to saturate it)
double getRate() Returns the stable rate in the RateLimiter configuration in licenses per second
void setRate(double permitsPerSecond) updates the stable rate of RateLimite. The parameter permitsPerSecond is provided by the factory method that constructs RateLimiter.
String toString() Returns the character representation of the object
boolean tryAcquire() Get the permission from RateLimiter, if the permission can be obtained immediately without delay
boolean tryAcquire(int permits) Get the number of permissions from RateLimiter, If the number of permits can be obtained immediately without delay
boolean tryAcquire(int permits, long timeout, TimeUnit unit) Gets the specified number from RateLimiter Number of licenses. If the number of licenses can be obtained within a time period that does not exceed the timeout, or if the number of licenses cannot be obtained before the timeout expires, then false is returned immediately (no need to wait)
boolean tryAcquire(long timeout, TimeUnit unit) Obtains permission from RateLimiter If the permission can be obtained within a time not exceeding timeout, or if the permission cannot be obtained before timeout expires, then return immediately false (no need to wait)

Start posting code

pom.xml

<!--guava RateLimiter限流-->
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
</dependency>

Custom interface Limit

package com.zjy.knife4j.inte;
import java.lang.annotation.*;
/**
 * 限流注解
 */
@Inherited
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Limit {
    // 默认每秒放入桶中的token
    double limitNum() default 20;
    String name() default "";
}

aop aspect

package com.zjy.knife4j.aspect;
import com.google.common.util.concurrent.RateLimiter;
import com.zjy.knife4j.inte.Limit;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
@Aspect
@Component
public class RateLimitAspect {
    /**日志对象*/
    private static final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
    private ConcurrentHashMap<String, RateLimiter> RATE_LIMITER  = new ConcurrentHashMap<>();
    private RateLimiter rateLimiter;
    @Pointcut("@annotation(com.zjy.knife4j.inte.Limit)")
    public void serviceLimit() {
    }
    @Around("serviceLimit()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object obj = null;
        //获取拦截的方法名
        Signature sig = point.getSignature();
        //获取拦截的方法名
        MethodSignature msig = (MethodSignature) sig;
        //返回被织入增加处理目标对象
        Object target = point.getTarget();
        //为了获取注解信息
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        //获取注解信息
        Limit annotation = currentMethod.getAnnotation(Limit.class);
        double limitNum = annotation.limitNum(); //获取注解每秒加入桶中的token
        String functionName = msig.getName(); // 注解所在方法名区分不同的限流策略
        if(RATE_LIMITER.containsKey(functionName)){
            rateLimiter=RATE_LIMITER.get(functionName);
        }else {
            RATE_LIMITER.put(functionName, RateLimiter.create(limitNum));
            rateLimiter=RATE_LIMITER.get(functionName);
        }
        if(rateLimiter.tryAcquire()) {
            logger.info("执行成功!!!...做一些业务处理");
            return point.proceed();
        } else {
            logger.info("请求繁忙...做一些业务处理");
            return null;
        }
    }
}

RateLimiterController

package com.zjy.knife4j.controller;
import com.zjy.knife4j.inte.Limit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/ratelimiter")
@RestController
public class RateLimiterController {
    /**
     * 开启限流
     * @return
     */
    @GetMapping("/open")
    @Limit(limitNum = 1, name = "test1")
    public String openRateLimiter1() {
        System.out.println("【限流执行了....编写业务....】");
        return "限流执行了";
    }
    /**
     * 开启限流
     * @return
     */
    @GetMapping("/open2")
    @Limit(limitNum = 1, name = "test2")
    public String openRateLimiter2() {
        System.out.println("【限流执行了222】");
        return "限流执行了222";
    }
    /**
     * 未开启限流
     * @return
     */
    @GetMapping("/close")
    public String closeRateLimiter() {
        System.out.println("【不限流执行了】");
        return "不限流执行了";
    }
}

After pasting the code, start testing

Start the service and access the interface that adds the current limiting annotation

How to use springboot to integrate RateLimiter current limiting

Visit the unannotated interface again

How to use springboot to integrate RateLimiter current limiting

The console prints the result:

How to use springboot to integrate RateLimiter current limiting

The above is the detailed content of How to use springboot to integrate RateLimiter current limiting. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete