Spring Cloud 中断路器 Circuit Breaker的应用

时间:2021-09-28 15:47:37

Spring Cloud 中断路器 Circuit Breaker的应用

环境:Springboot2.3.12.RELEASE +

cloud-netflix-hystrix2.2.10.RELEASE

简介

SpringCloud Circuit breaker(断路器)提供了跨不同断路器实现的抽象。它提供了在应用程序中使用的一致API,允许开发人员选择最适合应用程序需要的断路器实现。

支持的断路器类型:

  • Netfix Hystrix
  • Resilience4J
  • Sentinel
  • Spring Retry

核心概念

要在代码中创建断路器(circuit breaker),可以使用断路器工厂API。当您在类路径中包含Spring Cloud Circuit Breaker starter时,将自动创建一个实现此API的bean。下面给出了使用此API的一个非常简单的示例:

  1. @Service
  2. public static class DemoService {
  3. private RestTemplate rest;
  4. private CircuitBreakerFactory cbFactory;
  5. public DemoService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
  6. this.rest = rest;
  7. this.cbFactory = cbFactory;
  8. }
  9. public String slow() {
  10. // 通过默认的CircuitBreakerFactory工厂创建一个指定id(名称)的断路器
  11. // run方法是实际执行你的业务方法,第二个参数throwable 是当发生异常或者是执行超时
  12. // 执行的回退(降级)处理
  13. return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
  14. }
  15. }

项目配置

通过引入下面不同依赖来确定使用具体的那个断路器

  • Hystrix - org.springframework.cloud:spring-cloud-starter-netflix-hystrix
  • Resilience4J - org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j
  • Reactive Resilience4J - org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j
  • Spring Retry - org.springframework.cloud:spring-cloud-starter-circuitbreaker-spring-retry
  • Sentinal - org.springframework.cloud:spring-cloud-starter-circuitbreaker-sentinal

以上5种断路器是不同的实现方式,根据需要引入即可。

示例

这里以Hystrix为例来使用

引入依赖

  1. org.springframework.cloud
  2. spring-cloud-starter-netflix-hystrix
  3. 2.2.10.RELEASE

定义具有熔断功能的服务

  1. @Service
  2. public class DemoService {
  3. private RestTemplate rest;
  4. // 注入系统默认的实现
  5. private CircuitBreakerFactory cbFactory;
  6. public DemoService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
  7. this.rest = rest;
  8. this.cbFactory = cbFactory;
  9. }
  10. public String slow() {
  11. // 使用系统默认的实现创建断路器进行业务的处理
  12. return cbFactory.create("slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback");
  13. }
  14. public String slow2() {
  15. // 使用自定义的断路器工厂进行业务的处理
  16. return cbf().create("demo-slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback");
  17. }
  18. // 可以将这个定义为Bean来覆盖系统默认的实现,在系统默认的实现上有条件限定
  19. private CircuitBreakerFactory cbf() {
  20. HystrixCircuitBreakerFactory cbf = new HystrixCircuitBreakerFactory() ;
  21. // 配置线程池
  22. HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter() ;
  23. threadPoolProperties.withCoreSize(5)
  24. .withKeepAliveTimeMinutes(5)
  25. .withMaxQueueSize(Integer.MAX_VALUE)
  26. .withQueueSizeRejectionThreshold(1000) ;
  27. // 配置默认的执行行为属性
  28. HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter() ;
  29. commandProperties.withCircuitBreakerEnabled(true)
  30. // 当请求超过了3s那么断路器就会工作进行回退(降级处理),执行上面run方法中的第二个参数
  31. .withExecutionTimeoutInMilliseconds(3000)
  32. .withRequestCacheEnabled(true)
  33. // 隔离策略有两种THREAD,SEMAPHORE
  34. // THREAD: 避免线程被阻塞
  35. // SEMAPHORE: 适合高并发限流处理;因为线程池的方式一般不会创建过多的线程
  36. // 线程是有限的,在高并发情况下是没法满足响应处理的。
  37. .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD);
  38. // 将其加入到集合中,为不同的服务创建不同的配置
  39. cbf.configure(builder -> {
  40. builder.commandProperties(commandProperties).groupName("demo") ;
  41. }, "demo-slow");
  42. // 当默认的id不存在时使用这默认的配置
  43. cbf.configureDefault(id -> {
  44. HystrixCommand.Setter setter = HystrixCommand.Setter
  45. .withGroupKey(HystrixCommandGroupKey.Factory.asKey("demo")) // 服务分组,大的模块
  46. .andCommandKey(HystrixCommandKey.Factory.asKey("demo-slow")) // 服务标识(具体服务分组中的某一个子的服务),子模块
  47. .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("demo-pools")) // 线程池名称
  48. .andThreadPoolPropertiesDefaults(threadPoolProperties) // 线程池相关配置
  49. .andCommandPropertiesDefaults(commandProperties) ; // 执行时相关属性配置
  50. return setter ;
  51. });
  52. return cbf ;
  53. }
  54. }

Controller接口

  1. @RestController
  2. @RequestMapping("/demos")
  3. public class DemoController {
  4. @Resource
  5. private DemoService demoService ;
  6. @GetMapping("/index")
  7. public Object index() {
  8. return demoService.slow2() ;
  9. }
  10. @GetMapping("/slow")
  11. public Object slow() {
  12. try {
  13. TimeUnit.SECONDS.sleep(5) ;
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. return "slow" ;
  18. }
  19. }

原理

CircuitBreakerFactory#create方法创建了CircuitBreaker实例

根据当前的CLASSPATH我们使用的是Hystrix,那么这里使用的工厂就是:

HystrixCircuitBreakerFactory类

  1. public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory {

泛型参数:Setter就是用来配置Hystrix相关配置信息的(这里主要用来CommandKey与Setter进行绑定),HystrixConfigBuilder用来构建 HystrixCommand.Setter对象。

当执行HystrixCircuitBreakerFactory#configure方法时:

  1. public abstract class AbstractCircuitBreakerFactory> {
  2. private final ConcurrentHashMap configurations = new ConcurrentHashMap<>();
  3. public void configure(Consumer consumer, String... ids) {
  4. for (String id : ids) {
  5. // 构建一个Builder对象
  6. CONFB builder = configBuilder(id);
  7. // 这里通过builder(HystrixConfigBuilder)对象来应用Consumer中编写的配置信息
  8. consumer.accept(builder);
  9. // 构建HystrixCommand.Setter 对象
  10. CONF conf = builder.build();
  11. // 最后将通过id 与 Setter对象绑定key=value存入Map集合中
  12. getConfigurations().put(id, conf);
  13. }
  14. }
  15. // 该方法在子类HystrixCircuitBreakerFactory中实现
  16. protected abstract CONFB configBuilder(String id);
  17. }

断路器具体的子类实现HystrixCircuitBreakerFactory

  1. // 子类继承的父类中的泛型:第一个泛型参数:需要构建什么样的一个配置,第二个泛型参数:通过谁来构建第一个泛型参数配置
  2. public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory {
  3. public HystrixConfigBuilder configBuilder(String id) {
  4. return new HystrixConfigBuilder(id);
  5. }
  6. public static class HystrixConfigBuilder extends AbstractHystrixConfigBuilder {
  7. public HystrixConfigBuilder(String id) {
  8. super(id);
  9. }
  10. // 从这里也看出来最终Builder就是用来构建Setter对象用
  11. @Override
  12. public HystrixCommand.Setter build() {
  13. return HystrixCommand.Setter.withGroupKey(getGroupKey())
  14. .andCommandKey(getCommandKey())
  15. .andCommandPropertiesDefaults(getCommandPropertiesSetter());
  16. }
  17. }
  18. }

断路器工厂有了,接下来就是通过工厂创建具体的断路器对象了

通过上面的代码执行cbf().create("demo-slow")方法时执行了什么?

  1. public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory {
  2. private Function defaultConfiguration = id -> HystrixCommand.Setter
  3. .withGroupKey(HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName()))
  4. .andCommandKey(HystrixCommandKey.Factory.asKey(id));
  5. public HystrixCircuitBreaker create(String id) {
  6. // 通过上面分析最终所有的Hystrix的Setter会与id绑定存入一个Map中
  7. // 这里computeIfAbsent方法先从集合中通过id获取,如果获取不到则将第二个参数存入集合中返回
  8. HystrixCommand.Setter setter = getConfigurations().computeIfAbsent(id, defaultConfiguration);
  9. return new HystrixCircuitBreaker(setter);
  10. }
  11. }

上面创建的是HystrixCircuitBreaker断路器,当执行run方法时:

  1. public class HystrixCircuitBreaker implements CircuitBreaker {
  2. private HystrixCommand.Setter setter;
  3. public HystrixCircuitBreaker(HystrixCommand.Setter setter) {
  4. this.setter = setter;
  5. }
  6. @Override
  7. public T run(Supplier toRun, Function fallback) {
  8. // 最终执行的就是Hystrix的核心 HystrixCommand对象
  9. HystrixCommand command = new HystrixCommand(setter) {
  10. @Override
  11. protected T run() throws Exception {
  12. return toRun.get();
  13. }
  14. @Override
  15. protected T getFallback() {
  16. return fallback.apply(getExecutionException());
  17. }
  18. };
  19. return command.execute();
  20. }
  21. }

原文链接:https://www.toutiao.com/a7036197230167982630/