引入jar
<dependency>
<groupId>com.lkl.framework</groupId>
<artifactId>rate-limiter</artifactId>
<version>0.0.3-SNAPSHOT</version>
</dependency>
在需要限流的方法上加注解@RateLimit,通过类的全限定名称+.方法名+.rate配置速率,单位为qps,例如
package com.lkl.framework.services.controller;
@RestController
public class HelloWorldController {
@RateLimit()
public void sayHello(){
System.out.println("hello rate limiter");
}
}在配置文件中配置 com.lkl.framework.services.controller.HelloWorldController.sayHello.rate=10 表示该sayHello()方法限流为10qps
ps: com.lkl.framework.limiter.default.rate 可以设置全局默认速率
@RateLimit注解定义为
/**
* Created by liaokailin on 16/8/29.
*/
watchdog@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
public String name() default "" ; //default is (class name + method name)
public Strategy strategy() default Strategy.reject; //default is reject strategy,if can't acquire permit will reject request
public long timeOut() default 0l; // timeUnit is millisecond ,it work when strategy is reject,if can't acquire permit will wait {timeOut}ms,still can't allowed and reject request.
public long warmupPeriod() default 0l ; // timeUnit is millisecond the duration of the period where the {@code RateLimiter} ramps up its rate, before reaching its stable (maximum) rate
/**
* it work when strategy is reject,implements reject logic.
*/
public Class<? extends RejectedExecutionHandler> rejectedExecutionHandler() default RejectedExecutionHandler.DefaultRejectedExecutionHandler.class;
/**
* the strategy of resource is limited
*/
public enum Strategy{
/**
* if can't acquire permit will wait for accepted
*/
await,
/**
* if can't acquire permit will reject request
*/
reject
}
}| 配置项 | 默认 | 含义 |
|---|---|---|
| name | 类名+"."+方法名 | 指定该注解名称,通过name+.rate配置限流速率 |
| strategy | Strategy.reject | 当速率过快时处理请求的策略; Strategy.reject表示直接拒绝请求, Strategy.await表示等待接受请求 |
| timeOut | 0 | 当策略为Strategy.reject生效,等待timeOut时间后拒绝请求,单位毫秒 |
| rejectedExecutionHandler | RejectedExecutionHandler.DefaultRejectedExecutionHandler.class | 当策略为Strategy.reject生效,请求被拒绝后处理策略,默认抛出RateDefaultRejectException异常,可通过实现RejectedExecutionHandler自定义拒绝的处理逻辑 |
| warmupPeriod | 0 | 指定达到稳定速率时的预热时间,单位毫秒 |
@RateLimit注解基于spring aop实现,因此在使用该注解会受到spring aop的约束,例如:
1.spring aop不能拦截非public的方法,因此在如下代码上使用@RateLimit无效
@RateLimit()
private void sayHello(){
// some logic...
}2.spring aop不能拦截同一类中方法调用的另外一个方法上
public class Sample{
public void foo(){
this.bar(); // call inside another method
}
@RateLimit()
public void bar(){
// some logic...
}
}在上面代码中bar()上的注解无效,由于spring aop是围绕bean的,因此可以将bar()定义到另外一个bean中。
以上两种情况希望能规避.
在注解RateLimit中新增属性type 用依标注该限流类型
-
type=Type.DefaultMethodType.class(默认值)时表示对整个方法进行限流
-
type=CustomType.class或其子类时表示对该方法进行自定义的限流
type=Type.DefaultMethodType.class用以兼容老版本的功能,自定义类型进行拓展
其中CustomType.java实现为:
/**
* 自定义限流类型
* Created by liaokailin on 16/12/13.
*/
public interface CustomType extends Type {
/**
*
* @return 返回值用来区分自定义的限流策略,例如:按service token限流时 可返回clientId
*/
String name();
}假设在0.0.3以前版本配置速度方式为old.pattern.rate=xxx(该内容在前面的文档已说明),则新版本配置速率方式为
-
type=Type.DefaultMethodType.class,保持老的方式不变
-
type=CustomType.class或其子类时,配置方式为
old.pattern.{0}.rate=xxx其中{0}占位参数用CustomType中的name()方法返回结果填充
com.lkl.framework.limiter.default.rate 仍可设置全局默认速率
对方法A按照不同的clientId进行限流,则可利用service token去获取clientId 然后针对不同的clientId去配置速率即可
增加TokenType.java 该类name()返回clientId
public class TokenType implements CustomType {
@Override
public String name() {
return getClientId();
}
public static String getClientId() {
return JSON.parseObject(MDC.get("jwtClaims").toString(), Map.class).get("clientId").toString();
}
}在方法上使用
package com.lkl.framework.services.controller;
public class ToolsTestController {
@RateLimit( type = TokenType.class)
public void testRate() {
//do something
}
}使用如下配置:
com.lkl.framework.service.limiter.default.rate=20
com.lkl.framework.services.controller.ToolsTestController.testRate.security-client.rate=4
com.lkl.framework.services.controller.ToolsTestController.testRate.message-manager.rate=10
该配置表示全局速率为20qps, clientId为security-client限流4qps,message-manager限流10qps .