英文:
Resilience4J Ratelimiter does not limit access of annotated method
问题
我正在使用resilience4j-spring-boot2
库(io.github.resilience4j:resilience4j-spring-boot2
,版本1.5.0
)和Spring Boot版本2.3.1.RELEASE
。
我创建了一个RateLimiter
,它应该只允许一个线程每30秒执行某个方法。但是,似乎没有边界(除了Tomcat服务器中运行的配置线程数)来调用该方法的线程。
我实现了一个简单的服务,它等待一定的时间,然后返回"Hello!":
@RequestMapping("/")
@RestController
public class ResilientService {
@RateLimiter(name = "hello-rl")
@GetMapping("/hello/{timeout}")
public String hello(@PathVariable int timeout) throws InterruptedException {
Thread.sleep(timeout);
return "Hello!";
}
}
并配置了RateLimiter如下:
resilience4j.ratelimiter:
instances:
hello-rl:
limitForPeriod: 1 # 在一个限制刷新周期内可用的权限数
limitRefreshPeriod: 30s # 限制刷新的周期。在每个周期后,速率限制器将其权限计数设置回limitForPeriod值
timeoutDuration: 30s # 线程等待权限的默认等待时间
然后我使用了八个线程调用了该服务:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
@Slf4j
public class CircuitBreakerTest {
@Autowired
TestRestTemplate testRestTemplate;
@LocalServerPort
private int port;
@Value("${server.address}")
private String serverAddress;
@Test
public void t() throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(8);
for (int i : IntStream.rangeClosed(1, 8).toArray()) {
executorService.execute(() -> log.error(callService()));
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
private String callService() {
return testRestTemplate.getForObject(
"http://" + serverAddress + ":" + port + "/hello/5000",
String.class
);
}
}
输出结果如下:
2020-08-07 10:41:10,095 ERROR [pool-1-thread-7] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-1] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-8] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-2] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-5] CircuitBreakerTest: Hello!
2020-08-07 10:41:15,104 ERROR [pool-1-thread-3] CircuitBreakerTest: Hello!
2020-08-07 10:41:15,121 ERROR [pool-1-thread-4] CircuitBreakerTest: Hello!
2020-08-07 10:41:15,121 ERROR [pool-1-thread-6] CircuitBreakerTest: Hello!
只有五个线程似乎被允许同时执行该方法,但我不知道为什么。Tomcat服务器正在运行超过8个线程。我犯了错误吗?还是我误解了RateLimiter应该如何工作?
英文:
I am using the resilience4j-spring-boot2
library (io.github.resilience4j:resilience4j-spring-boot2
, version 1.5.0
) and Spring Boot version 2.3.1.RELEASE
.
I created a RateLimiter
which should only let one thread execute a certain method every 30 seconds. However, there does not seem to be a boundary (except for configurated number of threads running in the Tomcat server) for threads to call the method.
I implemented a simple Service which waits for a given amount of time and then returns "Hello!":
@RequestMapping("/")
@RestController
public class ResilientService {
@RateLimiter(name = "hello-rl")
@GetMapping("/hello/{timeout}")
public String hello(@PathVariable int timeout) throws InterruptedException {
Thread.sleep(timeout);
return "Hello!";
}
}
And configured the Ratelimiter as follows
resilience4j.ratelimiter:
instances:
hello-rl:
limitForPeriod: 1 # The number of permissions available during one limit refresh period
limitRefreshPeriod: 30s # The period of a limit refresh. After each period the rate limiter sets its permissions count back to the limitForPeriod value
timeoutDuration: 30s # The default wait time a thread waits for a permission
And I called the service with eight threads:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
@Slf4j
public class CircuitBreakerTest {
@Autowired
TestRestTemplate testRestTemplate;
@LocalServerPort
private int port;
@Value("${server.address}")
private String serverAddress;
@Test
public void t() throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(8);
for (int i : IntStream.rangeClosed(1, 8).toArray()) {
executorService.execute(() -> log.error(callService()));
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
private String callService() {
return testRestTemplate.getForObject(
"http://" + serverAddress + ":" + port + "/hello/5000",
String.class
);
}
The output is as follows:
2020-08-07 10:41:10,095 ERROR [pool-1-thread-7] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-1] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-8] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-2] CircuitBreakerTest: Hello!
2020-08-07 10:41:10,095 ERROR [pool-1-thread-5] CircuitBreakerTest: Hello!
2020-08-07 10:41:15,104 ERROR [pool-1-thread-3] CircuitBreakerTest: Hello!
2020-08-07 10:41:15,121 ERROR [pool-1-thread-4] CircuitBreakerTest: Hello!
2020-08-07 10:41:15,121 ERROR [pool-1-thread-6] CircuitBreakerTest: Hello!
Only five threads seem to be allowed to execute the method at one time, but I don't know why. The Tomcat server is running with >8 threads.
Did I make a mistake? Or am I misunderstanding how the RateLimiter is supposed to work?
答案1
得分: 4
resilience4j-spring-boot2
内部使用了切面,所以需要将 spring-boot-starter-aop
依赖添加到项目中,以使注解起作用:
<dependency>
<!-- 用于限流 -->
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>${resilience4j.version}</version>
</dependency>
<dependency>
<!-- Resilience4j 所需 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
如 官方文档 在“Setup”部分中所述... 完全错过了那个部分。
英文:
resilience4j-spring-boot2
uses aspects internally, so it is needed to add the spring-boot-starter-aop
dependency to the project for the annotations to work:
<dependency>
<!-- for rate limiting -->
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>${resilience4j.version}</version>
</dependency>
<dependency>
<!-- needed for Resilience4j -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
As stated in the official documentation right at the beginning ("Setup")... totally missed that.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论