Spring Cloud 中断路器 Circuit Breaker 的应用

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

[[439483]]

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

项目配置

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

  • 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. <dependency> 
  2.   <groupId>org.springframework.cloud</groupId> 
  3.   <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> 
  4.   <version>2.2.10.RELEASE</version> 
  5. </dependency> 

定义具有熔断功能的服务

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

Controller接口

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

原理

CircuitBreakerFactory#create方法创建了CircuitBreaker实例。

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

HystrixCircuitBreakerFactory类

  1. public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> { 

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

当执行HystrixCircuitBreakerFactory#configure方法时:

  1. public abstract class AbstractCircuitBreakerFactory<CONF, CONFB extends ConfigBuilder<CONF>> { 
  2.   private final ConcurrentHashMap<String, CONF> configurations = new ConcurrentHashMap<>(); 
  3.   public void configure(Consumer<CONFB> 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); 

断路器具体的子类实现

HystrixCircuitBreakerFactory

  1. // 子类继承的父类中的泛型:第一个泛型参数:需要构建什么样的一个配置,第二个泛型参数:通过谁来构建第一个泛型参数配置 
  2. public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> { 
  3.   public HystrixConfigBuilder configBuilder(String id) { 
  4.     return new HystrixConfigBuilder(id); 
  5.   } 
  6.   public static class HystrixConfigBuilder extends AbstractHystrixConfigBuilder<HystrixCommand.Setter> { 
  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.   } 

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

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

  1. public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> { 
  2.   private Function<String, HystrixCommand.Setter> 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.   } 

 上面创建的是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> T run(Supplier<T> toRun, Function<Throwable, T> fallback) { 
  8.     // 最终执行的就是Hystrix的核心 HystrixCommand对象 
  9.     HystrixCommand<T> command = new HystrixCommand<T>(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.   } 

 

责任编辑:姜华 来源: 今日头条
相关推荐

2021-12-15 08:15:26

Spring Circuit BreSpring Clou

2022-10-08 11:39:56

断路器Golang项目

2022-09-15 15:25:47

spring-微服务

2023-03-13 08:02:55

断路器应用API

2023-11-06 08:25:33

项目远程接口

2017-09-20 09:46:38

Spring BootSpring Clou内存

2020-07-03 08:00:11

Spring BootSpring Clou流程

2021-01-14 07:54:19

Spring Clou应用路由

2024-04-03 08:58:48

软件架构隔板

2013-05-23 13:31:38

路由器路由器故障路由器故障排除

2021-11-16 11:45:00

SpringSpring ClouJava

2021-01-14 08:13:39

Spring Clou应用内置过滤器

2020-10-21 09:00:15

Azure Sprin云服务日志
点赞
收藏

51CTO技术栈公众号