摘要:以下是它的示例現(xiàn)在,如果需要的話,所有對已修飾的服務塊的調用都要符合速率限制器配置。
案例概述
在本文中,我們討論一下Resilience4j庫。
該庫通過管理遠程通信的容錯性來幫助實現(xiàn)彈性系統(tǒng)。
這個庫受到Hystrix的啟發(fā),但提供了更方便的API和許多其他特性,如速率限制器(阻塞太頻繁的請求)、Bulkhead(避免太多并發(fā)請求)等。
Maven設置
首先,我們需要將目標模塊添加到我們的pom.xml中(例如,我們添加了Circuit Breaker):
???? io.github.resilience4j ????resilience4j-circuitbreaker ????0.12.1
在這里,我們使用的是斷路器模塊。所有模塊及其最新版本均可在Maven Central上找到。
在接下來的部分中,我們將介紹庫中最常用的模塊。
斷路器
請注意,對于此模塊,我們需要上面顯示的設置resilience4j-circuitbreaker依賴項。
斷路器模式可以幫助我們在遠程服務中斷時防止一連串的故障。
在多次失敗的嘗試之后,我們可以認為服務不可用/重載,并急切地拒絕所有后續(xù)的請求。通過這種方式,我們可以為可能失敗的調用節(jié)省系統(tǒng)資源。
讓我們看看我們如何通過Resilience4j實現(xiàn)這一目標。
首先,我們需要定義要使用的設置。最簡單的方法是使用默認設置:
CircuitBreakerRegistry circuitBreakerRegistry ??= CircuitBreakerRegistry.ofDefaults();
也可以使用自定義參數(shù):
CircuitBreakerConfig config = CircuitBreakerConfig.custom() ??.failureRateThreshold(20) ??.ringBufferSizeInClosedState(5) ??.build();
在這里,我們將速率閾值設置為20%,并將嘗試呼叫設置為最少5次。
然后,我們創(chuàng)建一個CircuitBreaker對象并通過它調用遠程服務:
interface RemoteService { ????int process(int i); } ? CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config); CircuitBreaker circuitBreaker = registry.circuitBreaker("my"); Functiondecorated = CircuitBreaker ??.decorateFunction(circuitBreaker, service::process);
最后,讓我們通過JUnit測試看看它是如何工作的。
我們將嘗試調用服務10次。我們應該能夠驗證該呼叫至少嘗試了5次,然后在20%的呼叫失敗后停止:
when(service.process(any(Integer.class))).thenThrow(new RuntimeException()); ? for (int i = 0; i < 10; i++) { ????try { ????????decorated.apply(i); ????} catch (Exception ignore) {} } ? verify(service, times(5)).process(any(Integer.class));
斷路器的狀態(tài)和設置
斷路器可以處于以下三種狀態(tài)之一:
CLOSED - 一切正常,不涉及短路
OPEN - 遠程服務器已關閉,所有請求都被短路
HALF_OPEN - 從進入開放狀態(tài)到現(xiàn)在已經(jīng)經(jīng)過了一段時間,斷路器允許請求檢查遠程服務是否重新上線
我們可以配置以下設置:
斷路器打開并開始短路呼叫的故障率閾值
等待時間,它定義了斷路器在切換到半開狀態(tài)之前應該保持打開狀態(tài)的時間
斷路器半開或半閉時環(huán)形緩沖器的尺寸
處理斷路器事件的定制電路斷路器事件監(jiān)聽器
一個自定義謂詞,用于評估異常是否應算作故障,從而提高故障率
速率限制器
與上一節(jié)類似,此功能需要resilience4j-ratelimiter依賴項。
顧名思義,此功能允許限制對某些服務的訪問。它的API與CircuitBreaker非常相似- 有Registry,Config和Limiter類。
以下是它的示例:
RateLimiterConfig config = RateLimiterConfig.custom().limitForPeriod(2).build(); RateLimiterRegistry registry = RateLimiterRegistry.of(config); RateLimiter rateLimiter = registry.rateLimiter("my"); Functiondecorated ??= RateLimiter.decorateFunction(rateLimiter, service::process);
現(xiàn)在,如果需要的話,所有對已修飾的服務塊的調用都要符合速率限制器配置。
我們可以配置如下參數(shù):
限制刷新的時間段
刷新周期的權限限制
默認等待權限持續(xù)時間
Bulkhead
在這里,我們首先需要relasticience4j-bulkhead依賴項。
可以限制對特定服務的并發(fā)調用數(shù)。
讓我們看一個使用Bulkhead API配置最多一個并發(fā)調用的示例:
BulkheadConfig config = BulkheadConfig.custom().maxConcurrentCalls(1).build(); BulkheadRegistry registry = BulkheadRegistry.of(config); Bulkhead bulkhead = registry.bulkhead("my"); Functiondecorated ??= Bulkhead.decorateFunction(bulkhead, service::process);
要測試此配置,我們將調用模擬服務的方法。
然后,我們確保Bulkhead不允許任何其他調用:
CountDownLatch latch = new CountDownLatch(1); when(service.process(anyInt())).thenAnswer(invocation -> { ????latch.countDown(); ????Thread.currentThread().join(); ????return null; }); ? ForkJoinTask> task = ForkJoinPool.commonPool().submit(() -> { ????try { ????????decorated.apply(1); ????} finally { ????????bulkhead.onComplete(); ????} }); latch.await(); assertThat(bulkhead.isCallPermitted()).isFalse();
我們可以配置以下設置:
Bulkhead允許的最大并行執(zhí)行量
嘗試進入飽和艙壁時線程等待的最長時間
重試
對于此功能,我們需要將resilience4j-retry庫添加到項目中。
我們可以使用Retry API 自動重試失敗的呼叫:
RetryConfig config = RetryConfig.custom().maxAttempts(2).build(); RetryRegistry registry = RetryRegistry.of(config); Retry retry = registry.retry("my"); Functiondecorated ??= Retry.decorateFunction(retry, (Integer s) -> { ????????service.process(s); ????????return null; ????});
現(xiàn)在讓我們模擬在遠程服務調用期間拋出異常的情況,并確保庫自動重試失敗的調用:
when(service.process(anyInt())).thenThrow(new RuntimeException()); try { ????decorated.apply(1); ????fail("Expected an exception to be thrown if all retries failed"); } catch (Exception e) { ????verify(service, times(2)).process(any(Integer.class)); }
我們還可以配置以下內容:
最大嘗試次數(shù)
重試前的等待時間
自定義函數(shù),用于修改失敗后的等待間隔
自定義謂詞,用于評估異常是否應導致重試調用
緩存
Cache模塊需要resilience4j-cache依賴項。
初始化看起來與其他模塊略有不同:
javax.cache.Cache cache = ...; // Use appropriate cache here CachecacheContext = Cache.of(cache); Function decorated ??= Cache.decorateSupplier(cacheContext, () -> service.process(1));
這里的緩存是通過使用JSR-107 Cache實現(xiàn)完成的,Resilience4j提供了一種應用它的方法。
請注意,沒有用于裝飾功能的API(如Cache.decorateFunction(Function)),API僅支持 Supplier和Callable類型。
TimeLimiter
對于此模塊,我們必須添加resilience4j-timelimiter依賴項。
可以使用TimeLimiter限制調用遠程服務所花費的時間。
為了演示,讓我們設置一個配置超時為1毫秒的TimeLimiter:
long ttl = 1; TimeLimiterConfig config ??= TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(ttl)).build(); TimeLimiter timeLimiter = TimeLimiter.of(config);
接下來,讓我們驗證Resilience4j是否使用預期的超時調用Future.get():
Future futureMock = mock(Future.class); Callable restrictedCall ??= TimeLimiter.decorateFutureSupplier(timeLimiter, () -> futureMock); restrictedCall.call(); ? verify(futureMock).get(ttl, TimeUnit.MILLISECONDS);
我們也可以將它與CircuitBreaker結合使用:
Callable chainedCallable ??= CircuitBreaker.decorateCallable(circuitBreaker, restrictedCall);
附加模塊
Resilience4j還提供了許多附加模塊,可以簡化與流行框架和庫的集成。
一些比較知名的集成是:
Spring Boot – resilience4j-spring-boot
Ratpack – resilience4j-ratpack
Retrofit – resilience4j-retrofit
Vertx – resilience4j-vertx
Dropwizard – resilience4j-metrics
Prometheus – resilience4j-prometheus
案例結論
在本文中,我們了解了Resilience4j庫的各個方面,并學習了如何使用它來解決服務器間通信中的各種容錯問題。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/73168.html
摘要:客戶端限速作為服務的消費者,我們希望確保我們不會使服務提供者過載。調優(yōu)客戶端和服務器端速率限制器實現(xiàn)客戶端速率限制并不能保證我們永遠不會受到上游服務的速率限制。 在本系列的上一篇文章中,我們了解了 Resilience4j 以及如何使用其 Retry 模塊。現(xiàn)在讓我們了解 RateLimiter - 它是什么,...
摘要:在上面打開一個微服務某個實例的一個路徑的斷路器之后,我們調用其他的路徑,無論多少次,都成功并且調用負載均衡器獲取服務實例的次數(shù)等于調用次數(shù),代表沒有重試,也就是沒有斷路器異常。 本系列代碼地址:??https://github.com/JoJoTec/spring-cloud-parent??我們來測試下前面封裝好的 We...
摘要:本系列代碼地址我們繼續(xù)上一節(jié),繼續(xù)使用測試我們自己封裝的測試針對重試測試針對重試針對響應超時,我們需要驗證重試僅針對可以重試的方法包括方法以及配置的可重試方法,針對不可重試的方法沒有重試。本系列代碼地址:https://github.com/JoJoTec/spring-cloud-parent我們繼續(xù)上一節(jié),繼續(xù)使用 spock 測試我們自己封裝的 WebClient測試針對 readTi...
摘要:重試會增加的響應時間。提供了輔助方法來為包含遠程調用的函數(shù)式接口或表達式創(chuàng)建裝飾器。如果我們想創(chuàng)建一個裝飾器并在代碼庫的不同位置重用它,我們將使用。 在本文中,我們將從快速介紹 Resilience4j 開始,然后深入探討其 Retry 模塊。我們將了解何時、如何使用它,以及它提供的功能。在此過程中,我們還將學...
摘要:本系列代碼地址上一節(jié)我們通過單元測試驗證了線程隔離的正確性,這一節(jié)我們來驗證我們斷路器的正確性,主要包括驗證配置正確加載即我們在配置例如中的加入的的配置被正確加載應用了。本系列代碼地址:https://github.com/JoJoTec/spring-cloud-parent上一節(jié)我們通過單元測試驗證了線程隔離的正確性,這一節(jié)我們來驗證我們斷路器的正確性,主要包括:驗證配置正確加載:即我們...
閱讀 3207·2021-09-22 15:05
閱讀 2763·2019-08-30 15:56
閱讀 1071·2019-08-29 17:09
閱讀 805·2019-08-29 15:12
閱讀 2088·2019-08-26 11:55
閱讀 3074·2019-08-26 11:52
閱讀 3382·2019-08-26 10:29
閱讀 1386·2019-08-23 17:19