時間が経過すると、システムは一定の 1/QPS 時間間隔に従います (QPS=100 の場合、間隔は 10 ミリ秒です) バケツにトークンを追加します (漏れの逆を想像してください。常に水を追加する蛇口があります)、バケツがいっぱいの場合、それ以上追加されません。新しいリクエストが来ると、それぞれがトークンを奪います。利用可能なトークンがない場合は、サービスがブロックまたは拒否されます。
トークン バケットのもう 1 つの利点は、速度を簡単に変更できることです。速度を上げる必要がある場合は、必要に応じて増やしてバケットに入れます。トークンのレート。一般に、特定の数のトークンが定期的にバケットに追加されます (100 ミリ秒など)。一部のバリアント アルゴリズムは、追加する必要があるトークンの数を計算します。
トークン バケットは、一般的に使用されるトラフィック制御テクノロジです。トークン バケット自体には、破棄ポリシーや優先ポリシーはありません。
1.トークンは一定の割合でバケットに入れられます。
2.各トークンにより、ソースは特定のビット数を送信できます。
3.パケットを送信するために、トラフィック コンディショナーはパケット サイズと同じ数のトークンをバケットから削除します。
4.パケットを送信するのに十分なトークンがない場合、パケットは十分なトークンが揃うまで待機するか (シェーパーの場合)、パケットはドロップされ、場合によってはより低い DSCP でマークされます (ポリシーラーの場合)。 ####5.バケットには特定の容量があり、バケットがいっぱいになると、新しく追加されたトークンは破棄されます。したがって、ソースがいつでもネットワーク上に送信できるバースト データの最大量はバケット サイズに比例します。トークン バケットではバーストが許可されますが、制限を超えることはできません。
#メソッドの概要
double | |
double | |
static RateLimiter | |
static RateLimiter | |
double | |
void | |
String | |
boolean | |
boolean | |
#boolean | |
boolean | |
コードの投稿を開始 |
<!--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>
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 アスペクト
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 "不限流执行了"; } }
コードを貼り付けた後、テストを開始します
サービスを開始し、現在の制限アノテーションを追加するインターフェイスにアクセスします
##注釈のないインターフェイスに再度アクセスします
コンソールに結果が表示されます:
以上がSpringboot を使用して RateLimiter 電流制限を統合する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。