Netflix Hystrix 斷路器是 Spring Cloud 中最早就開始支持的一種服務調用容錯解決方案,但是目前的 Hystrix 已經處於維護模式了,雖然這並不影響已經上線的項目,並且在短期內,你甚至也可以繼續在項目中使用 Hystrix 。但是長遠來看,處於維護狀態的 Hystrix 走下歷史舞台只是一個時間問題,特別是在 Spring Cloud Greenwich 版中,官方已經給出了 Hystrix 的建議替代方案。如下圖:
Resilience4j 是 Spring Cloud Greenwich 版推薦的容錯解決方案,它是一個輕量級的容錯庫,受 Netflix Hystrix 的啟發而設計,它專為 Java 8 和函數式編程而設計。
Resilience4j 非常輕量級,因為它的庫只使用 Vavr (以前稱為 Javaslang ),它沒有任何其他外部庫依賴項。相比之下, Netflix Hystrix 對Archaius 具有編譯依賴性,這導致了更多的外部庫依賴,例如 Guava 和 Apache Commons 。而如果使用Resilience4j,你無需引用全部依賴,可以根據自己需要的功能引用相關的模塊即可。
Resilience4j 也提供了一系列增強微服務可用性的功能,主要功能如下:
- 斷路器
- 限流
- 基於信號量的隔離
- 緩存
- 限時
- 請求重試
接下來,我們就先來看通過一個普通的Maven項目來看 Resilience4j 中這幾個功能的基本用法。
上面提到的 Resilience4j 中的功能,每一個功能都對應了一個依賴。我們創建好Maven項目后,再添加單元測試依賴:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
一、Resilience4j 的功能介紹
斷路器有三種正常狀態:完全打開OPEN,半開HALF_OPEN,關閉CLOSED,還有兩種通過設置的強制狀態:強制不可用DISABLED,強制打開FORCED_OPEN。
斷路器初始化
使用 Resilience4j 提供的斷路器功能,需要我們首先加入如下依賴:
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-circuitbreaker</artifactId> <version>1.5.0</version> </dependency>
這個庫提供了一個基於 ConcurrentHashMap 的 CircuitBreakerRegistry ,CircuitBreakerRegistry 是線程安全的,並且是原子操作。開發者可以使用 CircuitBreakerRegistry 來創建和檢索 CircuitBreaker 的實例 ,開發者可以直接使用默認的全局CircuitBreakerConfig 為所有 CircuitBreaker 實例創建 CircuitBreakerRegistry ,如下所示:
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults();
當然開發者也可以提供自己的 CircuitBreakerConfig ,然后根據自定義的 CircuitBreakerConfig 來創建一個 CircuitBreakerRegistry 實例,進而創建 CircuitBreaker 實例。如果我們使用自定義的 CircuitBreakerConfig :
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .failureRateThreshold(50) //默認為50,即失敗率閾值為50%, 超過這個閾值,斷路器就會打開 .waitDurationInOpenState(Duration.ofMillis(1000)) // 用來指定斷路器從OPEN到HALF_OPEN狀態等待的時長,默認是60秒 .permittedNumberOfCallsInHalfOpenState(2) //熔斷器半開時的限制線程的並發量 .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 滑動窗口類型,有基於時間TIME_BASED和基於計數COUNT_BASED .slidingWindowSize(2) //滑動窗口大小,默認是基於計數的滑動窗口類型 .automaticTransitionFromOpenToHalfOpenEnabled(false) //當waitDurationInOpenState時間一過,是否自動從OPEN切換到HALF_OPEN,默認為false .build(); // 配置CircuitBreakerRegistry CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig); // 創建兩個斷路器 CircuitBreaker circuitBreaker2 = circuitBreakerRegistry.circuitBreaker("otherName"); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("uniqueName", circuitBreakerConfig);
如果開發者不想使用 CircuitBreakerRegistry 來管理斷路器,那么也可以直接創建一個 CircuitBreaker 對象,創建方式如下:
CircuitBreaker defaultCircuitBreaker = CircuitBreaker.ofDefaults("testName");
CircuitBreaker customCircuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig);
斷路器使用案例
斷路器使用了裝飾者模式,開發者可以使用 CircuitBreaker.decorateCheckedSupplier(), CircuitBreaker.decorateCheckedRunnable() 或者 CircuitBreaker.decorateCheckedFunction() 來裝飾 Supplier / Runnable / Function 或者 CheckedRunnable / CheckedFunction,然后使用 Try.of(…) 或者 Try.run(…) 來進行調用操作,也可以使用 map、flatMap、filter、recover 或者 andThen 進行鏈式調用,但是調用這些方法斷路器必須處於 CLOSED 或者 HALF_OPEN 狀態。例如下面一個例子,創建一個斷路器出來,首先裝飾了一個函數,這個函數返回一段字符串,然后使用 Try.of 去執行,執行完后再進入到 map 中去執行。如果第一個函數正常執行第二個函數才會執行,如果第一個函數執行失敗,那么 map 函數將不會執行。