当前位置:   article > 正文

Spring Boot集成Resilience4J实现限流/重试/隔离

Spring Boot集成Resilience4J实现限流/重试/隔离

1.前言

上篇文章讲了Resilience4J实现熔断功能,文章详见:Spring Boot集成Resilience4J实现断路器功能 | Harries Blog™,本篇文章主要讲述基于Resilience4J实现限流/重试/隔离。

2.代码工程

pom.xml

  1. <dependency>
  2. <groupId>io.github.resilience4j</groupId>
  3. <artifactId>resilience4j-spring-boot3</artifactId>
  4. <version>2.0.2</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.projectlombok</groupId>
  8. <artifactId>lombok</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-aop</artifactId>
  13. </dependency>
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-actuator</artifactId>
  17. </dependency>

限流

  1. @RequestMapping("/hello")
  2. @RateLimiter(name="ratelimitApi",fallbackMethod = "fallback")
  3. public ResponseEntity<String> showHelloWorld(){
  4. return new ResponseEntity<>("success",HttpStatus.OK);
  5. }
  6. public ResponseEntity fallback(Throwable e){
  7. log.error("fallback exception , {}",e.getMessage());
  8. return new ResponseEntity<>("your request is too fast,please low down", HttpStatus.OK);
  9. }

重试

  1. @RequestMapping("/retry")
  2. @Retry(name = "backendA")//use backendA ,if throw IOException ,it will be retried 3 times
  3. public ResponseEntity<String> retry(String name){
  4. if(name.equals("test")){
  5. i++;
  6. log.info("retry time:{}",i);
  7. throw new HttpServerErrorException(HttpStatusCode.valueOf(101));
  8. }
  9. return new ResponseEntity<>("retry",HttpStatus.OK);
  10. }

隔离

  1. @RequestMapping("/bulkhead")
  2. @Bulkhead(name = "backendA")
  3. public ResponseEntity<String> bulkhead(){
  4. return new ResponseEntity<>("bulkhead",HttpStatus.OK);
  5. }

配置文件

  1. spring:
  2. application.name: resilience4j-demo
  3. jackson.serialization.indent_output: true
  4. management:
  5. endpoints.web.exposure.include:
  6. - '*'
  7. endpoint.health.show-details: always
  8. health.circuitbreakers.enabled: true
  9. resilience4j:
  10. circuitbreaker:
  11. configs:
  12. default:
  13. registerHealthIndicator: true
  14. slidingWindowSize: 10
  15. minimumNumberOfCalls: 5
  16. permittedNumberOfCallsInHalfOpenState: 3
  17. automaticTransitionFromOpenToHalfOpenEnabled: true
  18. waitDurationInOpenState: 5s
  19. failureRateThreshold: 50
  20. eventConsumerBufferSize: 10
  21. ratelimiter:
  22. instances:
  23. ratelimitApi:
  24. limit-for-period: 5
  25. limit-refresh-period: 1s
  26. timeout-duration: 100ms
  27. retry:
  28. instances:
  29. backendA:
  30. maxAttempts: 3
  31. waitDuration: 10s
  32. enableExponentialBackoff: true
  33. exponentialBackoffMultiplier: 2
  34. retryExceptions:
  35. - org.springframework.web.client.HttpServerErrorException
  36. - java.io.IOException
  37. bulkhead:
  38. instances:
  39. backendA:
  40. maxConcurrentCalls: 10

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

3.测试

1.启动Spring Boot应用程序

测试限流

  1. public class ThreadTest {
  2. public static void main(String[] args) {
  3. for(int i=0;i<6;i++){
  4. new Thread(()->{
  5. System.out.println(new RestTemplate().getForObject("http://localhost:8080/hello",String.class));
  6. }).start();
  7. }
  8. }
  9. }

运行main方法

  1. io.github.resilience4j.bulkhead.BulkheadFullException: Bulkhead 'backendA' is full and does not permit further calls
  2. at io.github.resilience4j.bulkhead.BulkheadFullException.createBulkheadFullException(BulkheadFullException.java:49) ~[resilience4j-bulkhead-2.0.2.jar:2.0.2]
  3. at io.github.resilience4j.bulkhead.internal.SemaphoreBulkhead.acquirePermission(SemaphoreBulkhead.java:164) ~[resilience4j-bulkhead-2.0.2.jar:2.0.2]
  4. at io.github.resilience4j.bulkhead.Bulkhead.lambda$decorateCheckedSupplier$0(Bulkhead.java:68) ~[resilience4j-bulkhead-2.0.2.jar:2.0.2]
  5. at io.github.resilience4j.bulkhead.Bulkhead.executeCheckedSupplier(Bulkhead.java:471) ~[resilience4j-bulkhead-2.0.2.jar:2.0.2]
  6. at io.github.resilience4j.spring6.bulkhead.configure.BulkheadAspect.handleJoinPoint(BulkheadAspect.java:194) ~[resilience4j-spring6-2.0.2.jar:2.0.2]
  7. at io.github.resilience4j.spring6.bulkhead.configure.BulkheadAspect.proceed(BulkheadAspect.java:147) ~[resilience4j-spring6-2.0.2.jar:2.0.2]
  8. at io.github.resilience4j.spring6.bulkhead.configure.BulkheadAspect.lambda$bulkheadAroundAdvice$1(BulkheadAspect.java:120) ~[resilience4j-spring6-2.0.2.jar:2.0.2]
  9. at io.github.resilience4j.spring6.fallback.FallbackExecutor.execute(FallbackExecutor.java:37) ~[resilience4j-spring6-2.0.2.jar:2.0.2]
  10. at io.github.resilience4j.spring6.bulkhead.configure.BulkheadAspect.bulkheadAroundAdvice(BulkheadAspect.java:121) ~[resilience4j-spring6-2.0.2.jar:2.0.2]
  11. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
  12. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
  13. at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
  14. at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
  15. at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:637) ~[spring-aop-6.1.2.jar:6.1.2]

测试重试

访问http://127.0.0.1:8080/retry?name=test

  1. 2024-08-03T23:16:32.092+08:00 INFO 5097 --- [resilience4j-demo] [nio-8080-exec-9] c.e.r.controller.HelloWorldController : retry time:1
  2. 2024-08-03T23:16:42.120+08:00 INFO 5097 --- [resilience4j-demo] [nio-8080-exec-9] c.e.r.controller.HelloWorldController : retry time:2
  3. 2024-08-03T23:17:02.142+08:00 INFO 5097 --- [resilience4j-demo] [nio-8080-exec-9] c.e.r.controller.HelloWorldController : retry time:3
  4. 2024-08-03T23:17:02.165+08:00 ERROR 5097 --- [resilience4j-demo] [nio-8080-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.web.client.HttpServerErrorException: 101 SWITCHING_PROTOCOLS] with root cause
  5. org.springframework.web.client.HttpServerErrorException: 101 SWITCHING_PROTOCOLS
  6. at com.et.resilience4j.controller.HelloWorldController.retry(HelloWorldController.java:37) ~[classes/:na]
  7. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
  8. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
  9. at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
  10. at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
  11. at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:352) ~[spring-aop-6.1.2.jar:6.1.2]
  12. at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.1.2.jar:6.1.2]

测试隔离

  1. public class ThreadTest {
  2. public static void main(String[] args) {
  3. /* for(int i=0;i<6;i++){
  4. new Thread(()->{
  5. System.out.println(new RestTemplate().getForObject("http://localhost:8080/hello",String.class));
  6. }).start();
  7. }*/
  8. for(int i=0;i<11;i++){
  9. new Thread(()->{
  10. System.out.println(new RestTemplate().getForObject("http://localhost:8080/bulkhead",String.class));
  11. }).start();
  12. }
  13. }
  14. }

运行main方法

2024-08-03T23:17:36.943+08:00 ERROR 5097 --- [resilience4j-demo] [nio-8080-exec-5] c.e.r.controller.HelloWorldController : fallback exception , RateLimiter 'ratelimitApi' does not permit further calls

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/931159
推荐阅读
相关标签
  

闽ICP备14008679号