Resilience4jへのガイド
1概要
このチュートリアルでは、http://resilience4j.github.io/resilience4j/[Resilience4j]ライブラリについて説明します。
このライブラリは、リモート通信のフォールトトレランスを管理することによって、回復力のあるシステムを実装するのに役立ちます。
このライブラリはhttps://www.baeldung.com/introduction-to-hystrix[Hystrix]に触発されていますが、はるかに便利なAPIと、Rate Limiter(頻繁すぎるリクエストをブロックする)、Bulkhead(やめましょう)のようなその他の機能を多数提供します多数の同時リクエストなど)
2 Mavenのセットアップ
最初に、ターゲットモジュールを
pom.xml
に追加する必要があります(例えば、ここではサーキットブレーカーを追加します)
:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-circuitbreaker</artifactId>
<version>0.12.1</version>
</dependency>
ここでは、
__circuitbreaker
__moduleを使用しています。すべてのモジュールとその最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22io.github.resilience4j%22[Maven Central]にあります。
次のセクションでは、ライブラリの最も一般的に使用されるモジュールについて説明します。
3サーキットブレーカ
このモジュールには上記の
resilience4j-circuitbreaker
依存関係が必要です。
Circuit Breaker pattern
は、リモートサービスが停止したときのカスケード障害の防止に役立ちます。
-
試行に失敗した後、サービスが利用できない/過負荷になっていると見なし、それ以降のすべての要求を積極的に拒否します。このようにして、失敗する可能性が高い呼び出し用のシステムリソースを節約できます。
Resilience4jを使用してそれを達成する方法を見てみましょう。
まず、使用する設定を定義する必要があります。最も簡単な方法は、デフォルト設定を使用することです。
CircuitBreakerRegistry circuitBreakerRegistry
= CircuitBreakerRegistry.ofDefaults();
カスタムパラメータを使用することもできます。
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(20)
.ringBufferSizeInClosedState(5)
.build();
ここでは、料金しきい値を20%に設定し、最低5回の通話試行を設定します。
次に、
CircuitBreaker
オブジェクトを作成し、それを通してリモートサービスを呼び出します。
interface RemoteService {
int process(int i);
}
CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config);
CircuitBreaker circuitBreaker = registry.circuitBreaker("my");
Function<Integer, Integer> decorated = 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));
3.1.
サーキットブレーカの
状態と設定
CircuitBreaker
は、次の3つの状態のいずれかになります。
-
CLOSED
– すべて問題ありません。短絡は発生しません。 -
OPEN
– リモートサーバーがダウンしている、それに対するすべての要求が短絡されている -
HALF
OPEN__ – OPEN状態に入ってからの設定時間
が経過し、
CircuitBreaker
はリモートサービスがオンラインに戻ったかどうかを確認する要求を許可します
以下の設定を構成できます。
-
CircuitBreaker
が開き、それを超えると故障率のしきい値
ショートコールを開始します
**
CircuitBreaker
の長さを定義する待機期間
ハーフオープンに切り替わる前に開いたままにする
**
CircuitBreaker
が半分開いているときのリングバッファのサイズ
閉まっている
**
CircuitBreaker
を処理するカスタム
CircuitBreakerEventListener
イベント
** カスタム
Predicate
は、例外が
失敗して失敗率を増加させる
4レートリミッタ
前のセクションと同様に、この機能にはhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22resilience4j-ratelimiter%22[
resilience4j-ratelimiter
]依存関係が必要です。
その名前が示すように、
この機能により、一部のサービスへのアクセスを制限することができます
。そのAPIは
CircuitBreakerの
に非常に似ています –
Registry
、
Config
そして
Limiter
クラスがあります。
外観の例を次に示します。
RateLimiterConfig config = RateLimiterConfig.custom().limitForPeriod(2).build();
RateLimiterRegistry registry = RateLimiterRegistry.of(config);
RateLimiter rateLimiter = registry.rateLimiter("my");
Function<Integer, Integer> decorated
= RateLimiter.decorateFunction(rateLimiter, service::process);
レートリミッタ設定に準拠するために必要ならば今装飾されたサービスブロックのすべてのコール。
以下のようにパラメータを設定できます。
-
制限リフレッシュの期間
-
リフレッシュ期間の許可制限
-
デフォルトの許可待ち時間
5隔壁
ここでは、最初にhttps://search.maven.org/classic/#search%7Cga%7C1%7Cresilience4j-bulkhead[
resilience4j-bulkhead
]依存関係が必要です。
特定のサービスへの同時呼び出し数を制限することは可能です。
Bulkhead APIを使用して最大同時コール数を1つ設定する例を見てみましょう。
BulkheadConfig config = BulkheadConfig.custom().maxConcurrentCalls(1).build();
BulkheadRegistry registry = BulkheadRegistry.of(config);
Bulkhead bulkhead = registry.bulkhead("my");
Function<Integer, Integer> decorated
= 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();
以下の設定を構成できます。
-
バルクヘッドで許可される最大同時実行数
-
スレッドが入ろうとするときに待つ最大の時間
飽和隔壁
6. リトライ
この機能を使用するには、https://search.maven.org/classic/#search%7Cga%7C1%7Cresilience4j-retry[
resilience4j-retry
]ライブラリをプロジェクトに追加する必要があります。
Retry APIを使用して
失敗した通話を
自動的に再試行できます。
RetryConfig config = RetryConfig.custom().maxAttempts(2).build();
RetryRegistry registry = RetryRegistry.of(config);
Retry retry = registry.retry("my");
Function<Integer, Void> decorated
= Retry.decorateFunction(retry, (Integer s) -> {
service.process(s);
return null;
});
リモートサービス呼び出し中に例外がスローされる状況をエミュレートして、ライブラリが失敗した呼び出しを自動的に再試行するようにしましょう。
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));
}
以下を設定することもできます。
-
最大試行回数
-
再試行までの待機時間
-
失敗後の待機間隔を変更するためのカスタム関数
-
例外が発生するかどうかを評価するカスタム
Predicate
通話を再試行する
7. キャッシュ
Cacheモジュールにはhttps://search.maven.org/classic/#search%7Cga%7C1%7Cresilience4j-cache[
resilience4j-cache
]依存関係が必要です。
初期化は他のモジュールとは少し異なります。
javax.cache.Cache cache = ...;//Use appropriate cache here
Cache<Integer, Integer> cacheContext = Cache.of(cache);
Function<Integer, Integer> decorated
= Cache.decorateSupplier(cacheContext, () -> service.process(1));
ここでキャッシングは使用されるhttps://www.baeldung.com/jcache[JSR-107 Cache]実装によって行われ、Resilience4jはそれを適用する方法を提供します。
Cache.decorateFunction(Function)
のような関数を装飾するためのAPIはありません。APIは
Supplier
および
Callable
タイプのみをサポートします。
8 TimeLimiter
このモジュールでは、https://search.maven.org/classic/#search%7Cga%7C1%7Cresilience4j-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);
9アドオンモジュール
Resilience4jは、人気のあるフレームワークやライブラリとの統合を容易にする多数のアドオンモジュールも提供しています。
よく知られている統合のいくつかは以下のとおりです。
-
Spring Boot – resilience4j-spring-boot__モジュール
-
ラットパック –
resilience4j-ratpack
モジュール -
レトロフィット –
resilience4j-retrofit
モジュール -
Vertx –
resilience4j-vertx
モジュール -
Dropwizard –
resilience4j-metrics
モジュール -
Prometheus –
resilience4j-prometheus
モジュール
10結論
この記事では、Resilience4jライブラリーのさまざまな側面について説明し、サーバー間通信におけるさまざまなフォールトトレランスの問題に対処するための使用方法を学びました。
いつものように、上記のサンプルのソースコードはhttps://github.com/eugenp/tutorials/tree/master/libraries[over GitHub]にあります。