From 8fb712241ab4cef2a3cf4e73374f456e4131c808 Mon Sep 17 00:00:00 2001 From: YunaiV <> Date: Thu, 21 May 2020 08:22:19 +0800 Subject: [PATCH] =?UTF-8?q?resilience4j=20+=20=E7=9B=91=E6=8E=A7=20?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab-59/lab-59-resilience4j-actuator/pom.xml | 65 ++++++++++++++++++ .../resillience4jdemo/DemoApplication.java | 20 ++++++ .../controller/BulkheadDemoController.java | 30 +++++++++ .../controller/DemoController.java | 34 ++++++++++ .../controller/RateLimiterDemoController.java | 28 ++++++++ .../controller/RetryDemoController.java | 34 ++++++++++ .../ThreadPoolBulkheadDemoController.java | 49 ++++++++++++++ .../controller/TimeLimiterDemoController.java | 49 ++++++++++++++ .../src/main/resources/application.yml | 66 +++++++++++++++++++ lab-59/pom.xml | 1 + pom.xml | 2 +- 11 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 lab-59/lab-59-resilience4j-actuator/pom.xml create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java create mode 100644 lab-59/lab-59-resilience4j-actuator/src/main/resources/application.yml diff --git a/lab-59/lab-59-resilience4j-actuator/pom.xml b/lab-59/lab-59-resilience4j-actuator/pom.xml new file mode 100644 index 00000000..9f7c4637 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/pom.xml @@ -0,0 +1,65 @@ + + + + lab-59 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-59-resilience4j-actuator + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + io.github.resilience4j + resilience4j-spring-boot2 + 1.4.0 + + + + + org.aspectj + aspectjrt + 1.9.5 + + + org.aspectj + aspectjweaver + 1.9.5 + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java new file mode 100644 index 00000000..9f482e9d --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java @@ -0,0 +1,20 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java new file mode 100644 index 00000000..6937108a --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java @@ -0,0 +1,30 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/bulkhead-demo") +public class BulkheadDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @Bulkhead(name = "backendC", fallbackMethod = "getUserFallback", type = Bulkhead.Type.SEMAPHORE) + public String getUser(@RequestParam("id") Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java new file mode 100644 index 00000000..37882518 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @CircuitBreaker(name = "backendA", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java new file mode 100644 index 00000000..51f1b561 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java @@ -0,0 +1,28 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/rate-limiter-demo") +public class RateLimiterDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @RateLimiter(name = "backendB", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java new file mode 100644 index 00000000..23014c4a --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.retry.annotation.Retry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/retry-demo") +public class RetryDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @Retry(name = "backendE", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java new file mode 100644 index 00000000..8f27bb86 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/thread-pool-bulkhead-demo") +public class ThreadPoolBulkheadDemoController { + + @Autowired + private ThreadPoolBulkheadService threadPoolBulkheadService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + threadPoolBulkheadService.getUser0(id); + return threadPoolBulkheadService.getUser0(id).get(); + } + + @Service + public static class ThreadPoolBulkheadService { + + private Logger logger = LoggerFactory.getLogger(ThreadPoolBulkheadService.class); + + @Bulkhead(name = "backendD", fallbackMethod = "getUserFallback", type = Bulkhead.Type.THREADPOOL) + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java new file mode 100644 index 00000000..5c1f35d4 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/time-limiter-demo") +public class TimeLimiterDemoController { + + @Autowired + private TimeLimiterService timeLimiterService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + return timeLimiterService.getUser0(id).get(); + } + + @Service + public static class TimeLimiterService { + + private Logger logger = LoggerFactory.getLogger(TimeLimiterService.class); + + @Bulkhead(name = "backendD", type = Bulkhead.Type.THREADPOOL) + @TimeLimiter(name = "backendF", fallbackMethod = "getUserFallback") + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/resources/application.yml b/lab-59/lab-59-resilience4j-actuator/src/main/resources/application.yml new file mode 100644 index 00000000..d3736cfa --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/resources/application.yml @@ -0,0 +1,66 @@ +resilience4j: + # Resilience4j 的断路器配置项,对应 CircuitBreakerProperties 属性类 + circuitbreaker: + instances: + backendA: + failure-rate-threshold: 50 # 熔断器关闭状态和半开状态使用的同一个失败率阈值,单位:百分比。默认为 50 + ring-buffer-size-in-closed-state: 5 # 熔断器关闭状态的缓冲区大小,不会限制线程的并发量,在熔断器发生状态转换前所有请求都会调用后端服务。默认为 100 + ring-buffer-size-in-half-open-state: 5 # 熔断器半开状态的缓冲区大小,会限制线程的并发量。例如,缓冲区为 10 则每次只会允许 10 个请求调用后端服务。默认为 10 + wait-duration-in-open-state : 5000 # 熔断器从打开状态转变为半开状态等待的时间,单位:微秒 + automatic-transition-from-open-to-half-open-enabled: true # 如果置为 true,当等待时间结束会自动由打开变为半开;若置为 false,则需要一个请求进入来触发熔断器状态转换。默认为 true + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的限流器配置项,对应 RateLimiterProperties 属性类 + ratelimiter: + instances: + backendB: + limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 + limit-refresh-period: 10s # 每个周期的时长,单位:微秒。默认为 500 + timeout-duration: 5s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的信号量 Bulkhead 配置项,对应 BulkheadConfigurationProperties 属性类 + bulkhead: + instances: + backendC: + max-concurrent-calls: 1 # 并发调用数。默认为 25 + max-wait-duration: 5s # 并发调用到达上限时,阻塞等待的时长,单位:微秒。默认为 0 + # Resilience4j 的线程池 Bulkhead 配置项,对应 ThreadPoolBulkheadProperties 属性类 + thread-pool-bulkhead: + instances: + backendD: + max-thread-pool-size: 1 # 线程池的最大大小。默认为 Runtime.getRuntime().availableProcessors() + core-thread-pool-size: 1 # 线程池的核心大小。默认为 Runtime.getRuntime().availableProcessors() - 1 + queue-capacity: 200 # 线程池的队列大小。默认为 100 + keep-alive-duration: 100s # 超过核心大小的线程,空闲存活时间。默认为 20 毫秒 + + # Resilience4j 的重试 Retry 配置项,对应 RetryProperties 属性类 + retry: + instances: + backendE: + max-retry-Attempts: 3 # 最大重试次数。默认为 3 + wait-duration: 5s # 下次重试的间隔,单位:微秒。默认为 500 毫秒 + retry-exceptions: # 需要重试的异常列表。默认为空 + ingore-exceptions: # 需要忽略的异常列表。默认为空 + + # Resilience4j 的超时限制器 TimeLimiter 配置项,对应 TimeLimiterProperties 属性类 + timelimiter: + instances: + backendF: + timeout-duration: 1s # 等待超时时间,单位:微秒。默认为 1 秒 + cancel-running-future: true # 当等待超时时,是否关闭取消线程。默认为 true + +management: + endpoints: + # Actuator HTTP 配置项,对应 WebEndpointProperties 配置类 + web: + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + endpoint: + # Health 端点配置项,对应 HealthProperties 配置类 + health: + show-details: ALWAYS # 何时显示完整的健康信息。默认为 NEVER 都不展示。可选 WHEN_AUTHORIZED 当经过授权的用户;可选 ALWAYS 总是展示。 + # 健康检查配置项 + health: + circuitbreakers.enabled: true + ratelimiters.enabled: true diff --git a/lab-59/pom.xml b/lab-59/pom.xml index b05e21fa..c9b5e486 100644 --- a/lab-59/pom.xml +++ b/lab-59/pom.xml @@ -15,6 +15,7 @@ lab-59-user-service lab-59-resilience4j-demo01 + lab-59-resilience4j-actuator diff --git a/pom.xml b/pom.xml index 42170d7f..0d7279d1 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ - + lab-42