1. 程式人生 > >一個輕量級的容錯庫—Resilience4j,Hystrix的替代品,斷路器、限流、隔離艙、重試、快取全部搞定。

一個輕量級的容錯庫—Resilience4j,Hystrix的替代品,斷路器、限流、隔離艙、重試、快取全部搞定。

Netflix宣佈停止開發Hystrix,建議使用Resilience4j,Resilience4j到底是什麼鬼?Resilience4j最新版本為0.13.2,無論是案例還是活躍度,都不及Hystrix,帶著這些疑問,讓我們來了解一下Resilience4j。

首先,我先簡單對比一下二者。

  • 實際上Resilience4j的靈感來自於Hystrix,同樣是輕量級的分散式容錯方法庫,比Hystrix的功能更豐富一些;

  • Hystrix是基於Command模式的,而Resilience4j利用了Java 8 的函數語言程式設計思想;

  • Hystrix需要依賴於Archaius,Archaius又依賴於第三方庫Guava和Apache Commons Configuration,而Resilience4j只依賴Vavr庫(前身是Javaslang)。

Resilience4j的核心模組包括斷路器、限流、隔離艙、重試、快取等,他們都是獨立編譯的,如果你僅僅需要其中的一部分,則可以部分引入。

  • resilience4j-circuitbreaker: Circuit breaking

  • resilience4j-ratelimiter: Rate limiting

  • resilience4j-bulkhead: Bulkheading

  • resilience4j-retry: Automatic retrying (sync and async)

  • resilience4j-cache: Response caching

  • resilience4j-timelimiter: Timeout handling

話不多說,直接上程式碼,如何實現一個斷路器? 首先引入包,

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-circuitbreaker</artifactId>
    <version>0.13.1</version>
</dependency>`

建立一個自定義配置的斷路器,

CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
    .failureRateThreshold(80) //失敗率閾值百分比,以百分比形式配置故障率閾值,高於該百分比,CircuitBreaker應跳閘並開始呼叫短路。閾值必須大於0且不大於100.預設值為50%。
    .waitDurationInOpenState(Duration.ofMillis(1000))//等待持續時間,該持續時間指定CircuitBreaker在切換到半開之前應保持開啟的時間。預設60秒。
    .ringBufferSizeInHalfOpenState(20)//預設為100,狀態為半開啟時,環形緩衝區的大小,這裡需要注意,如果設定為20,則必須要評估20次呼叫,才能計算出失敗率,少於19次,無論失敗率是多少都沒用。
    .ringBufferSizeInClosedState(20)
    .build();
//通過全域性配置建立斷路器
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);
CircuitBreaker circuitBreaker2 = circuitBreakerRegistry.circuitBreaker("otherName");
//當然,你也可以不使用全域性配置建立斷路器
CircuitBreaker defaultCircuitBreaker = CircuitBreaker.ofDefaults("testName");

這裡需要注意的是如果name相同,則認為是同一個斷路器。

@Test
public void shouldBeTheSameCircuitBreaker() {
    CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testName");
    CircuitBreaker circuitBreaker2 = circuitBreakerRegistry.circuitBreaker("testName");
    assertThat(circuitBreaker).isSameAs(circuitBreaker2);
    assertThat(circuitBreakerRegistry.getAllCircuitBreakers()).hasSize(1);
}

另外,你也可以通過Predicate過濾異常,也就是說,可以設定哪些異常可以觸發斷路器,哪些不觸發。

CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();
// 返回失敗百分比
float failureRate = metrics.getFailureRate();
// 返回當前緩衝的呼叫數
int bufferedCalls = metrics.getNumberOfBufferedCalls();
// 返回當前失敗的呼叫數
int failedCalls = metrics.getNumberOfFailedCalls();

當然,你可以可以基於AOP實現斷路器,

@CircuitBreaker(name = "backendA", recovery = MyRecoveryFunction.class)
@Singleton
public class BackendAConnector implements Connector {
    ...
}

也可以提供了介面獲取一些監控指標。可以和Prometheus整合。 

斷路器採用Ring Bit Buffer儲存開啟、關閉等狀態,使用了一個16位的long陣列,每個long 64 bit,這樣可以儲存1024次呼叫的狀態,非常節約儲存,值得借鑑。

 

其他模組用法類似,可以參考官網。

 

總結:大概瀏覽了一下原始碼,程式碼質量不錯,邏輯清晰,可讀性非常高。幾乎可以不用看註釋、文件,可以預見,resilience4j一定是一個未來被很多框架引用的基礎庫。

 

參考:https://github.com/resilience4j/resilience4j