1. 什么是resilience4j
有时我们不想让某个接口被访问得太过频繁,想对访问量进行控制,这时resilience4j就可以发挥作用了。
官方文档:https://resilience4j.readme.io/v1.7.0/docs/getting-started
2. 如何使用resilience4j
resilience4j提供了数种限流的规则,这里我们主要介绍两种:RateLimiter 和 Bulkhead。
2.1 RateLimiter
频率限制器,RateLimiter可以让你控制某个方法在一段时间内的访问量,比如你想限制某个方法在1s内只能被访问10次,就可以使用RateLimiter实现。
我们在springboot种使用RateLimiter,有以下几个步骤:
2.1.1 引入依赖
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
<version>1.7.0</version>
</dependency>
2.1.2 添加配置
在spring配置文件中,添加如下配置
#较为宽松的限流
resilience4j.ratelimiter.instances.rateLimiter_relaxedMod.limit-for-period=60
resilience4j.ratelimiter.instances.rateLimiter_relaxedMod.limit-refresh-period=500ms
resilience4j.ratelimiter.instances.rateLimiter_relaxedMod.timeout-duration=10s
#较为严格的限流
resilience4j.ratelimiter.instances.rateLimiter_strictMod.limit-for-period=10
resilience4j.ratelimiter.instances.rateLimiter_strictMod.limit-refresh-period=1s
resilience4j.ratelimiter.instances.rateLimiter_strictMod.timeout-duration=0
配置属性 | 默认值 | 解释 |
---|---|---|
timeoutDuration | 5s | 线程等待获取权限的等待时间 |
limitRefreshPeriod | 500ns | 限制刷新的时间段。在每个周期之后,速率限制器将其权限计数设置回 limitForPeriod 值 |
limitForPeriod | 50 | 一个限制刷新期间可用的权限数 |
上面我们配置了rateLimiter_relaxedMod和rateLimiter_strictMod两种舱壁,这个名字可以自定义,后面在使用RateLimiter的时候可以通过这个名字来指定使用哪种规则。
-
rateLimiter_relaxedMod我们配置了在500ms内允许60个请求通过,如果在500ms周期内60个请求数量已经被消耗完,则第61个请求会阻塞等待10s,当进入下一个500ms周期时,此第61个请求会获得执行权限。
-
rateLimiter_strictMod我们配置了在1s内允许10个请求通过,如果在1s周期内10个请求数量已经被消耗完,则第11个请求会直接报错,不阻塞等待。
2.1.3 方法限流
完成上述配置后,就可以将限流规则引入到方法上了,引入的方式也非常简单,直接在方法上添加注解就可以了。
@RateLimiter(name = "rateLimiter_relaxedMod")
public String test1() {
return "hello world1";
}
@RateLimiter(name = "rateLimiter_strictMod")
public String test2() {
return "hello world2";
}
如代码中所示,我们在方法上添加注解RateLimiter,并通过name指定了我们使用哪个RateLimiter作为这个方法的限流规则,这就完成方法的限流了。
注意:注解需要添加到接口的实现上,不能直接添加到接口上,否则不生效。
2.2 Bulkhead
可以翻译为舱壁,Bulkhead的作用是限制一个方法最多同时被多少个线程调用。
我们在springboot种使用Bulkhead,有以下几个步骤:
2.2.1 引入依赖
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-bulkhead</artifactId>
<version>1.7.0</version>
</dependency>
2.2.2 添加配置
在spring配置文件中,添加如下配置
#较为宽松的限流
resilience4j.bulkhead.instances.bulkhead_relaxedMod.max-concurrent-calls=50
resilience4j.bulkhead.instances.bulkhead_relaxedMod.max-wait-duration=20ms
#较为严格的限流
resilience4j.bulkhead.instances.bulkhead_strictMod.max-concurrent-calls=25
配置属性 | 默认值 | 解释 |
---|---|---|
maxConcurrentCalls | 25 | 舱壁允许的最大并行执行量 |
maxWaitDuration | 0 | 尝试进入饱和舱壁时应阻塞线程的最长时间 |
上面我们配置了bulkhead_relaxedMod和bulkhead_strictMod两种舱壁,这个名字可以自定义,后面在使用舱壁的时候可以通过这个名字来指定使用哪种规则。
-
bulkhead_relaxedMod我们配置了最大同时调用线程数是50,如果最大线程数已经达到50,则第51个线程调用此方法时,会阻塞等待20ms,如果20ms内依然没有空位可以进去,则此第51个线程直接返回报错,不再阻塞等待。
-
bulkhead_strictMod我们配置了最大同时调用线程数是25,如果最大线程数已经达到25,则第26个线程调用此方法时,不会阻塞等待,直接返回报错。
2.2.3 方法限流
完成上述配置后,就可以将限流规则引入到方法上了,引入的方式也非常简单,直接在方法上添加注解就可以了。
@Bulkhead(name = "bulkhead_relaxedMod")
public String test1() {
return "hello world1";
}
@Bulkhead(name = "bulkhead_strictMod")
public String test2() {
return "hello world2";
}
如代码中所示,我们在方法上添加注解@Bulkhead,并通过name指定了我们使用哪个bulkhead作为这个方法的限流规则,这就完成方法的限流了。
注意:注解需要添加到接口的实现上,不能直接添加到接口上,否则不生效。
2.3 混合使用
我们可以混合使用RateLimiter和Bulkhead,把两个注解同时添加到方法上就行了。
@Bulkhead(name = "bulkhead_relaxedMod")
@RateLimiter(name = "rateLimiter_relaxedMod")
public String test1() {
return "hello world1";
}
@Bulkhead(name = "bulkhead_strictMod")
@RateLimiter(name = "rateLimiter_strictMod")
public String test2() {
return "hello world2";
}
结合上面两者,方法首先需要获得RateLimiter的令牌才能执行,并且在有足够令牌的前提下,还需要检查Bulkhead是否有足够的并发容量来处理新的请求。