Rumah  >  Artikel  >  Java  >  Cara menggunakan springboot untuk menyepadukan pengehadan RateLimiter semasa

Cara menggunakan springboot untuk menyepadukan pengehadan RateLimiter semasa

WBOY
WBOYke hadapan
2023-05-12 10:40:061678semak imbas

Skema baldi token RateLimiter

Cara menggunakan springboot untuk menyepadukan pengehadan RateLimiter semasa

  • Apabila masa berlalu, sistem akan mengikut selang masa 1/QPS malar (jika QPS=100, Kemudian selang adalah 10ms) Tambah Token ke baldi (bayangkan kebalikan daripada kebocoran, terdapat paip sentiasa menambah air), jika baldi penuh, tiada lagi akan ditambah Apabila permintaan baru datang, masing-masing akan mengambil Token . Jika tiada token tersedia, ia akan menyekat atau menafikan perkhidmatan.

  • Faedah lain baldi token ialah ia boleh menukar kelajuan dengan mudah , tambahkannya mengikut keperluan dan masukkan ke dalam baldi Kadar token Secara amnya, bilangan token tertentu akan ditambahkan secara tetap (seperti 100 milisaat). dalam masa nyata

Timba token ialah teknologi kawalan trafik yang biasa digunakan. Baldi token itu sendiri tidak mempunyai dasar pembuangan dan keutamaan.

Prinsip

1. Token dimasukkan ke dalam baldi pada kadar tertentu.

2. Setiap token membenarkan sumber menghantar bilangan bit tertentu.

3. Untuk menghantar paket, perapi trafik mengeluarkan beberapa token daripada baldi yang sama dengan saiz paket.

4. Jika token tidak mencukupi untuk menghantar paket, paket menunggu sehingga token mencukupi (dalam kes pembentuk) atau paket digugurkan, mungkin ditandakan dengan DSCP yang lebih rendah (dalam kes polisi).

5. Baldi mempunyai kapasiti tertentu Jika baldi penuh, token yang baru ditambah akan dibuang. Oleh itu, jumlah maksimum data pecah sumber boleh menghantar ke rangkaian pada bila-bila masa adalah berkadar dengan saiz baldi. Baldi token membenarkan pecah, tetapi tidak boleh melebihi had.

Ringkasan kaedah

修饰符和类型 方法和描述
   
double acquire() 从RateLimiter获取一个许可,该方法会被阻塞直到获取到请求
double acquire(int permits) 从RateLimiter获取指定许可数,该方法会被阻塞直到获取到请求
static RateLimiter create(double permitsPerSecond) 根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)
static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) 根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少个请求量),在这段预热时间内,RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率。(只要存在足够请求数来使其饱和)
double getRate() 返回RateLimiter 配置中的稳定速率,该速率单位是每秒多少许可数
void setRate(double permitsPerSecond) 更新RateLimite的稳定速率,参数permitsPerSecond 由构造RateLimiter的工厂方法提供。
String toString() 返回对象的字符表现形式
boolean tryAcquire() 从RateLimiter 获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话
boolean tryAcquire(int permits) 从RateLimiter 获取许可数,如果该许可数可以在无延迟下的情况下立即获取得到的话
boolean tryAcquire(int permits, long timeout, TimeUnit unit) 从RateLimiter 获取指定许可数如果该许可数可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可数的话,那么立即返回false (无需等待)
boolean tryAcquire(long timeout, TimeUnit unit) 从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待)

Mulakan kod siaran

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>

Had antara muka tersuai

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 aspek

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 "不限流执行了";
    }
}

Selepas menampal kod, mula menguji

Mulakan perkhidmatan dan akses antara muka yang menambah anotasi mengehadkan semasa

Cara menggunakan springboot untuk menyepadukan pengehadan RateLimiter semasa

Lawati semula antara muka tanpa nota

Cara menggunakan springboot untuk menyepadukan pengehadan RateLimiter semasa

Hasil cetakan konsol:

Cara menggunakan springboot untuk menyepadukan pengehadan RateLimiter semasa

Atas ialah kandungan terperinci Cara menggunakan springboot untuk menyepadukan pengehadan RateLimiter semasa. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam