Spring Cloud 中斷路器 Circuit Breaker 的應(yīng)用
環(huán)境:Springboot2.3.12.RELEASE +
cloud-netflix-hystrix2.2.10.RELEASE
簡介
SpringCloud Circuit breaker(斷路器)提供了跨不同斷路器實現(xiàn)的抽象。它提供了在應(yīng)用程序中使用的一致API,允許開發(fā)人員選擇最適合應(yīng)用程序需要的斷路器實現(xiàn)。
支持的斷路器類型:
- Netfix Hystrix
- Resilience4J
- Sentinel
- Spring Retry
核心概念
要在代碼中創(chuàng)建斷路器(circuit breaker),可以使用斷路器工廠API。當(dāng)您在類路徑中包含Spring Cloud Circuit Breaker starter時,將自動創(chuàng)建一個實現(xiàn)此API的bean。下面給出了使用此API的一個非常簡單的示例:
- @Service
- public static class DemoService {
- private RestTemplate rest;
- private CircuitBreakerFactory cbFactory;
- public DemoService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
- this.rest = rest;
- this.cbFactory = cbFactory;
- }
- public String slow() {
- // 通過默認的CircuitBreakerFactory工廠創(chuàng)建一個指定id(名稱)的斷路器
- // run方法是實際執(zhí)行你的業(yè)務(wù)方法,第二個參數(shù)throwable 是當(dāng)發(fā)生異?;蛘呤菆?zhí)行超時
- // 執(zhí)行的回退(降級)處理
- return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
- }
- }
項目配置
通過引入下面不同依賴來確定使用具體的那個斷路器:
- 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種斷路器是不同的實現(xiàn)方式,根據(jù)需要引入即可。
示例
這里以Hystrix為例來使用
引入依賴
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
- <version>2.2.10.RELEASE</version>
- </dependency>
定義具有熔斷功能的服務(wù)
- @Service
- public class DemoService {
- private RestTemplate rest;
- // 注入系統(tǒng)默認的實現(xiàn)
- private CircuitBreakerFactory cbFactory;
- public DemoService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
- this.rest = rest;
- this.cbFactory = cbFactory;
- }
- public String slow() {
- // 使用系統(tǒng)默認的實現(xiàn)創(chuàng)建斷路器進行業(yè)務(wù)的處理
- return cbFactory.create("slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback");
- }
- public String slow2() {
- // 使用自定義的斷路器工廠進行業(yè)務(wù)的處理
- return cbf().create("demo-slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback");
- }
- // 可以將這個定義為Bean來覆蓋系統(tǒng)默認的實現(xiàn),在系統(tǒng)默認的實現(xiàn)上有條件限定
- private CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> cbf() {
- HystrixCircuitBreakerFactory cbf = new HystrixCircuitBreakerFactory() ;
- // 配置線程池
- HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter() ;
- threadPoolProperties.withCoreSize(5)
- .withKeepAliveTimeMinutes(5)
- .withMaxQueueSize(Integer.MAX_VALUE)
- .withQueueSizeRejectionThreshold(1000) ;
- // 配置默認的執(zhí)行行為屬性
- HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter() ;
- commandProperties.withCircuitBreakerEnabled(true)
- // 當(dāng)請求超過了3s那么斷路器就會工作進行回退(降級處理),執(zhí)行上面run方法中的第二個參數(shù)
- .withExecutionTimeoutInMilliseconds(3000)
- .withRequestCacheEnabled(true)
- // 隔離策略有兩種THREAD,SEMAPHORE
- // THREAD: 避免線程被阻塞
- // SEMAPHORE: 適合高并發(fā)限流處理;因為線程池的方式一般不會創(chuàng)建過多的線程
- // 線程是有限的,在高并發(fā)情況下是沒法滿足響應(yīng)處理的。
- .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD);
- // 將其加入到集合中,為不同的服務(wù)創(chuàng)建不同的配置
- cbf.configure(builder -> {
- builder.commandProperties(commandProperties).groupName("demo") ;
- }, "demo-slow");
- // 當(dāng)默認的id不存在時使用這默認的配置
- cbf.configureDefault(id -> {
- HystrixCommand.Setter setter = HystrixCommand.Setter
- .withGroupKey(HystrixCommandGroupKey.Factory.asKey("demo")) // 服務(wù)分組,大的模塊
- .andCommandKey(HystrixCommandKey.Factory.asKey("demo-slow")) // 服務(wù)標識(具體服務(wù)分組中的某一個子的服務(wù)),子模塊
- .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("demo-pools")) // 線程池名稱
- .andThreadPoolPropertiesDefaults(threadPoolProperties) // 線程池相關(guān)配置
- .andCommandPropertiesDefaults(commandProperties) ; // 執(zhí)行時相關(guān)屬性配置
- return setter ;
- });
- return cbf ;
- }
- }
Controller接口
- @RestController
- @RequestMapping("/demos")
- public class DemoController {
- @Resource
- private DemoService demoService ;
- @GetMapping("/index")
- public Object index() {
- return demoService.slow2() ;
- }
- @GetMapping("/slow")
- public Object slow() {
- try {
- TimeUnit.SECONDS.sleep(5) ;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return "slow" ;
- }
- }
原理
CircuitBreakerFactory#create方法創(chuàng)建了CircuitBreaker實例。
根據(jù)當(dāng)前的CLASSPATH我們使用的是Hystrix,那么這里使用的工廠就是:
HystrixCircuitBreakerFactory類
- public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> {
泛型參數(shù):Setter就是用來配置Hystrix相關(guān)配置信息的(這里主要用來CommandKey與Setter進行綁定),HystrixConfigBuilder用來構(gòu)建 HystrixCommand.Setter對象。
當(dāng)執(zhí)行HystrixCircuitBreakerFactory#configure方法時:
- public abstract class AbstractCircuitBreakerFactory<CONF, CONFB extends ConfigBuilder<CONF>> {
- private final ConcurrentHashMap<String, CONF> configurations = new ConcurrentHashMap<>();
- public void configure(Consumer<CONFB> consumer, String... ids) {
- for (String id : ids) {
- // 構(gòu)建一個Builder對象
- CONFB builder = configBuilder(id);
- // 這里通過builder(HystrixConfigBuilder)對象來應(yīng)用Consumer中編寫的配置信息
- consumer.accept(builder);
- // 構(gòu)建HystrixCommand.Setter 對象
- CONF conf = builder.build();
- // 最后將通過id 與 Setter對象綁定key=value存入Map集合中
- getConfigurations().put(id, conf);
- }
- }
- // 該方法在子類HystrixCircuitBreakerFactory中實現(xiàn)
- protected abstract CONFB configBuilder(String id);
- }
斷路器具體的子類實現(xiàn)
HystrixCircuitBreakerFactory
- // 子類繼承的父類中的泛型:第一個泛型參數(shù):需要構(gòu)建什么樣的一個配置,第二個泛型參數(shù):通過誰來構(gòu)建第一個泛型參數(shù)配置
- public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> {
- public HystrixConfigBuilder configBuilder(String id) {
- return new HystrixConfigBuilder(id);
- }
- public static class HystrixConfigBuilder extends AbstractHystrixConfigBuilder<HystrixCommand.Setter> {
- public HystrixConfigBuilder(String id) {
- super(id);
- }
- // 從這里也看出來最終Builder就是用來構(gòu)建Setter對象用
- @Override
- public HystrixCommand.Setter build() {
- return HystrixCommand.Setter.withGroupKey(getGroupKey())
- .andCommandKey(getCommandKey())
- .andCommandPropertiesDefaults(getCommandPropertiesSetter());
- }
- }
- }
斷路器工廠有了,接下來就是通過工廠創(chuàng)建具體的斷路器對象了。
通過上面的代碼執(zhí)行cbf().create("demo-slow")方法時執(zhí)行了什么?
- public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> {
- private Function<String, HystrixCommand.Setter> defaultConfiguration = id -> HystrixCommand.Setter
- .withGroupKey(HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName()))
- .andCommandKey(HystrixCommandKey.Factory.asKey(id));
- public HystrixCircuitBreaker create(String id) {
- // 通過上面分析最終所有的Hystrix的Setter會與id綁定存入一個Map中
- // 這里computeIfAbsent方法先從集合中通過id獲取,如果獲取不到則將第二個參數(shù)存入集合中返回
- HystrixCommand.Setter setter = getConfigurations().computeIfAbsent(id, defaultConfiguration);
- return new HystrixCircuitBreaker(setter);
- }
- }
上面創(chuàng)建的是HystrixCircuitBreaker斷路器,當(dāng)執(zhí)行run方法時:
- public class HystrixCircuitBreaker implements CircuitBreaker {
- private HystrixCommand.Setter setter;
- public HystrixCircuitBreaker(HystrixCommand.Setter setter) {
- this.setter = setter;
- }
- @Override
- public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
- // 最終執(zhí)行的就是Hystrix的核心 HystrixCommand對象
- HystrixCommand<T> command = new HystrixCommand<T>(setter) {
- @Override
- protected T run() throws Exception {
- return toRun.get();
- }
- @Override
- protected T getFallback() {
- return fallback.apply(getExecutionException());
- }
- };
- return command.execute();
- }
- }