使用Resilience4J實現斷路器模式
斷路器是一種模式,可以防止整個架構中單個微服務的故障級聯,從而確保系統具有彈性。該模式可以通過像Hystrix或Resilience4j這樣的程式碼庫實現,或者通過底層基礎設施來實現,例如使用Istio。
Hystrix vs. Resilience4j簡介
Hystrix是Netflix提供的一個開源庫,旨在提高分散式系統的彈性,使HTTP請求在其分散式元件之間進行通訊。它通過實現斷路器模式實現。
Resilience4J是一個受Hystrix啟發的獨立庫,它建立在功能程式設計的原理之上。兩者之間最顯著的區別在於,雖然Hystrix採用物件導向的設計,其中對外部系統的呼叫必須包含在HystrixCommand提供多種功能中,但Resilience4J依賴於函式組合來讓您堆疊所需的特定裝飾器。
那些裝飾器當然包括斷路器,還包括速率限制器,重試和隔板。這些裝飾器可以同步或非同步執行,充分利用Java 8中引入的lambda。
Resilience4J的其他優點包括更精細的配置選項(例如,關閉斷路器模式所需的成功執行次數)和更輕的依賴性足跡。
Java中的函式程式設計簡介
函式組合背後的想法是:
- 如果函式f被定義為Function<X, Y>- 將型別X作為輸入並返回型別的函式Y
- 如果函式g定義為Function<Y, Z>
- 然後可以將新函式h定義為Function<X, Z>組成函式f和g
Java 8在其API中引入了函式程式設計(FP)的一些方面。上面的函式組合可以在Java中翻譯:
public class F implements Function<Integer, Integer> { @Override public Integer apply(Integer x) { return x + 1; } } public class G implements Function<Integer, Integer> { @Override public Integer apply(Integer y) { return 2 * y; } } public class H implements Function<Integer, Integer> { @Override public Integer apply(Integer x) { var f = new F(); var g = new G(); Integer y = f.apply(x); return g.apply(y); } } |
這非常麻煩,因為Java最初設計時考慮了物件導向程式設計(OOP)。
一切都需要屬於一個類,即使這沒有多大意義。因此,為了彌合OOP和FP之間的這種差距,並使FP程式碼更容易編寫,Java 8帶來了函式介面的概念:功能介面是一個帶有單個抽象方法的介面,並且可選擇帶註釋@FunctionalInterface。
可以使用lambda表示法以簡化的方式編寫任何功能介面。例如,Function<T, V>是一個函式介面,因為它有一個抽象方法 - apply()。因此,可以使用lambdas重寫上面的程式碼:
Function<Integer, Integer> h = x -> { Function<Integer, Integer> f = y -> y + 1; Function<Integer, Integer> g = y -> y + 1; return g.apply(f.apply(x)); }; |
FP的另一個基礎是高階函式。這隻意味著函式是類似於任何其他型別的函式,並且可以作為函式中的引數傳遞,並作為結果返回。
例如,Functioninterface定義以下方法:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } |
使用這種方法,我們可以簡單地重寫h函式:
var h = f.compose(g); |
Resilience4J完全基於函數語言程式設計,並且使用了很多公開的概念。重要的是要記住從Hystrix遷移,因為與通常的Java思維方式相比,這需要進行更改。
Resilience4J入門
HTTP呼叫可以被認為是一個函式:它接受HTTP請求作為輸入,並返回HTTP響應。
同樣,Circuit Breaker可以被認為是一個函式,輸入相同的HTTP請求,返回值如果呼叫成功則返回HTTP響應,如果失敗則返回預設HTTP響應。
因此,使用斷路器就像用第二個“斷路器”函式組成第一個“呼叫”函式。
這是一個示例,用於說明如何使用它:
public class Command { public Long run() { // Does the actual job of making the HTTP request } } var cb = CircuitBreaker.ofDefaults("circuit-breaker"); var result = cb.executeSupplier(new Command()::run); |
因為Resilience4J中的每個特徵都被建模為一個函式,所以組合這些特徵只需要應用上述的函式組合原理。
這相當於物件導向程式設計中的Decorator模式:目標被“包裝”到裝飾器物件中。
在這裡,我們應用此設計來組成三個函式呼叫。第一個呼叫HTTP端點,第二個呼叫Circuit Breaker,第三個呼叫,如果呼叫失敗則重試。
var cb = CircuitBreaker.ofDefaults("circuit-breaker"); var retry = Retry.ofDefaults("retry"); var cbSupplier = CircuitBreaker.decorateSupplier(cb, new Command()::run); var retrySupplier = Retry.decorateSupplier(retry, cbSupplier); var result = retrySupplier.get(); |
自定義快取裝飾器
使用Resilience4J實現快取功能,我們的要求是:只有在修飾函式呼叫失敗時才應從快取返回。設計我們自己的快取實現功能非常簡單。“函式”這個詞很重要,因為根據Resilience4J的設計原則,狀態 - 快取 - 應該是外部的並傳遞給函式以保持其純淨。為了簡化實現,快取將保留一個值,當裝飾函式成功返回時,可能會替換該值:
public class Cache<T> { private T value; static <T> Supplier<T> decorateSupplier(Cache<T> cache, Supplier<T> supplier) { return Try.ofSupplier(supplier) .fold( throwable -> () -> cache.value, value -> { cache.value = value; return () -> value; }); } } |
本Try類來自於Vavr庫,函式程式設計API的Java語言和Resilience4J唯一的依賴。它需要兩個lambdas:
- 第一個接受一個 Throwable並返回一個返回結果的函式
- 第二個接受該值,並返回一個返回結果的函式
請注意,兩者都是惰性的:它們不直接返回結果,而是返回Supplier結果。使用此自定義快取,現在可以裝飾Circuit Breaker呼叫,以便在電路開啟時返回快取值:
var cb = CircuitBreaker.ofDefaults("circuit-breaker"); var cache = new Cache<Long>(); var cbDecorated = CircuitBreaker.decorateSupplier(cb, new Command()::run); var cacheDecorated = Cache.decorateSupplier(cache, cbDecorated); cacheDecorated.get(); |
相關文章
- Java 專案中使用 Resilience4j 框架實現隔斷機制/斷路器Java框架
- 使用Resilience4j實施反應式斷路器 - WenqiENQ
- 微服務斷路器模式實現:Istio vs Hystrix微服務模式
- Spring Boot中使用斷路器模式實現彈性微服務Spring Boot模式微服務
- 帶有Resilience4j斷路器的Spring雲閘道器 - romeSpring
- 使用Spring Boot + Resilience 4j實現斷路器Spring Boot
- resilience4j不夠用?自制分散式斷路器來幫忙 -Nicolas分散式
- Spring Cloud:使用Hystrix實現斷路器原理詳解(下)SpringCloud
- 使用 Resilience4j 框架實現重試機制框架
- Java 專案中使用 Resilience4j 框架實現故障隔離Java框架
- 冷飯新炒:理解斷路器CircuitBreaker的原理與實現UI
- Java 專案中使用 Resilience4j 框架實現非同步超時處理Java框架非同步
- 斷路器HystrixCircuitBreakerUI
- 智慧斷路器與傳統斷路器的區別?
- 採用斷路器設計模式來保護軟體設計模式
- 熔斷器設計模式設計模式
- 熔斷器 Hystrix 原始碼解析 —— 斷路器 HystrixCircuitBreaker原始碼UI
- Spring Cloud入門教程-Hystrix斷路器實現容錯和降級SpringCloud
- 使用函式式實現觀察者模式模式函式模式
- 使用C# (.NET Core) 實現迭代器設計模式 (Iterator Pattern)C#設計模式
- 07.CircuitBreaker斷路器UI
- 設計模式學習-使用go實現代理模式設計模式Go
- Java 8中實現構建器模式Java模式
- 從kratos分析breaker熔斷器原始碼實現原始碼
- Java 專案中使用 Resilience4j 實現客戶端 API 呼叫的限速/節流機制Java客戶端API
- resilience4j
- 設計模式:單例模式的使用和實現(JAVA)設計模式單例Java
- 設計模式學習-使用go實現觀察者模式設計模式Go
- 設計模式學習-使用go實現橋接模式設計模式Go橋接
- 設計模式學習-使用go實現裝飾模式設計模式Go
- 設計模式學習-使用go實現外觀模式設計模式Go
- 設計模式學習-使用go實現建造者模式設計模式Go
- 設計模式學習-使用go實現原型模式設計模式Go原型
- 設計模式學習-使用go實現單例模式設計模式Go單例
- 微服務架構 | 5.1 使用 Netflix Hystrix 斷路器微服務架構
- SpringCloud(三)Hystrix斷路器SpringGCCloud
- 使用spring外掛實現策略模式Spring模式
- node靜態伺服器斷點續傳實現伺服器斷點