環境: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的一個非常簡單的示例:
- @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工廠創建一個指定id(名稱)的斷路器
- // run方法是實際執行你的業務方法,第二個參數throwable 是當發生異常或者是執行超時
- // 執行的回退(降級)處理
- 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種斷路器是不同的實現方式,根據需要引入即可。
示例
這里以Hystrix為例來使用
引入依賴
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-hystrix -
2.2.10.RELEASE
定義具有熔斷功能的服務
- @Service
- public class DemoService {
- private RestTemplate rest;
- // 注入系統默認的實現
- private CircuitBreakerFactory cbFactory;
- public DemoService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
- this.rest = rest;
- this.cbFactory = cbFactory;
- }
- public String slow() {
- // 使用系統默認的實現創建斷路器進行業務的處理
- return cbFactory.create("slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback");
- }
- public String slow2() {
- // 使用自定義的斷路器工廠進行業務的處理
- return cbf().create("demo-slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback");
- }
- // 可以將這個定義為Bean來覆蓋系統默認的實現,在系統默認的實現上有條件限定
-
private CircuitBreakerFactory
cbf() { - HystrixCircuitBreakerFactory cbf = new HystrixCircuitBreakerFactory() ;
- // 配置線程池
- HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter() ;
- threadPoolProperties.withCoreSize(5)
- .withKeepAliveTimeMinutes(5)
- .withMaxQueueSize(Integer.MAX_VALUE)
- .withQueueSizeRejectionThreshold(1000) ;
- // 配置默認的執行行為屬性
- HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter() ;
- commandProperties.withCircuitBreakerEnabled(true)
- // 當請求超過了3s那么斷路器就會工作進行回退(降級處理),執行上面run方法中的第二個參數
- .withExecutionTimeoutInMilliseconds(3000)
- .withRequestCacheEnabled(true)
- // 隔離策略有兩種THREAD,SEMAPHORE
- // THREAD: 避免線程被阻塞
- // SEMAPHORE: 適合高并發限流處理;因為線程池的方式一般不會創建過多的線程
- // 線程是有限的,在高并發情況下是沒法滿足響應處理的。
- .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD);
- // 將其加入到集合中,為不同的服務創建不同的配置
- cbf.configure(builder -> {
- builder.commandProperties(commandProperties).groupName("demo") ;
- }, "demo-slow");
- // 當默認的id不存在時使用這默認的配置
- cbf.configureDefault(id -> {
- HystrixCommand.Setter setter = HystrixCommand.Setter
- .withGroupKey(HystrixCommandGroupKey.Factory.asKey("demo")) // 服務分組,大的模塊
- .andCommandKey(HystrixCommandKey.Factory.asKey("demo-slow")) // 服務標識(具體服務分組中的某一個子的服務),子模塊
- .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("demo-pools")) // 線程池名稱
- .andThreadPoolPropertiesDefaults(threadPoolProperties) // 線程池相關配置
- .andCommandPropertiesDefaults(commandProperties) ; // 執行時相關屬性配置
- 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方法創建了CircuitBreaker實例。
根據當前的CLASSPATH我們使用的是Hystrix,那么這里使用的工廠就是:
HystrixCircuitBreakerFactory類
-
public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory
{
泛型參數:Setter就是用來配置Hystrix相關配置信息的(這里主要用來CommandKey與Setter進行綁定),HystrixConfigBuilder用來構建 HystrixCommand.Setter對象。
當執行HystrixCircuitBreakerFactory#configure方法時:
-
public abstract class AbstractCircuitBreakerFactory
> { -
private final ConcurrentHashMap
configurations = new ConcurrentHashMap<>(); -
public void configure(Consumer
consumer, String... ids) { - for (String id : ids) {
- // 構建一個Builder對象
- CONFB builder = configBuilder(id);
- // 這里通過builder(HystrixConfigBuilder)對象來應用Consumer中編寫的配置信息
- consumer.accept(builder);
- // 構建HystrixCommand.Setter 對象
- CONF conf = builder.build();
- // 最后將通過id 與 Setter對象綁定key=value存入Map集合中
- getConfigurations().put(id, conf);
- }
- }
- // 該方法在子類HystrixCircuitBreakerFactory中實現
- protected abstract CONFB configBuilder(String id);
- }
斷路器具體的子類實現
HystrixCircuitBreakerFactory
- // 子類繼承的父類中的泛型:第一個泛型參數:需要構建什么樣的一個配置,第二個泛型參數:通過誰來構建第一個泛型參數配置
-
public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory
{ - public HystrixConfigBuilder configBuilder(String id) {
- return new HystrixConfigBuilder(id);
- }
-
public static class HystrixConfigBuilder extends AbstractHystrixConfigBuilder
{ - public HystrixConfigBuilder(String id) {
- super(id);
- }
- // 從這里也看出來最終Builder就是用來構建Setter對象用
- @Override
- public HystrixCommand.Setter build() {
- return HystrixCommand.Setter.withGroupKey(getGroupKey())
- .andCommandKey(getCommandKey())
- .andCommandPropertiesDefaults(getCommandPropertiesSetter());
- }
- }
- }
斷路器工廠有了,接下來就是通過工廠創建具體的斷路器對象了。
通過上面的代碼執行cbf().create("demo-slow")方法時執行了什么?
-
public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory
{ -
private Function
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獲取,如果獲取不到則將第二個參數存入集合中返回
- HystrixCommand.Setter setter = getConfigurations().computeIfAbsent(id, defaultConfiguration);
- return new HystrixCircuitBreaker(setter);
- }
- }
上面創建的是HystrixCircuitBreaker斷路器,當執行run方法時:
- public class HystrixCircuitBreaker implements CircuitBreaker {
- private HystrixCommand.Setter setter;
- public HystrixCircuitBreaker(HystrixCommand.Setter setter) {
- this.setter = setter;
- }
- @Override
-
public
T run(Supplier FunctiontoRun, fallback) { - // 最終執行的就是Hystrix的核心 HystrixCommand對象
-
HystrixCommand
command = new HystrixCommand (setter) { - @Override
- protected T run() throws Exception {
- return toRun.get();
- }
- @Override
- protected T getFallback() {
- return fallback.apply(getExecutionException());
- }
- };
- return command.execute();
- }
- }
原文鏈接:https://www.toutiao.com/a7036197230167982630/