リイクロサービスでサーバスを构筑する际,耐障害性を考虑して実装する事がとても重要です。 な概念です。
MicroProfileの容错はこうした,耐障害性のあるサービスを构筑するために必要な机能を提供しています。ます装実CDIによるアノテーション・ベースで容易に开発ができ,CDI クいます(クラスはCDIのBeanとして実装しなければなりません)。
Fault,ビジネス・ロジックとFault Torerance用の冗长的なコードを分离し,かんたんに実装できるようになっています。
MicroProfileの容错のポリシーは外部设定に外だしして管理することが可能になっており,MicroProfile Configを利用してポリシー管理を行うこともできます。
Fault Tolerance の仕様に含まれる主な機能
容错で提供する机能 | 使用するアノテーションと概要说明 |
---|---|
1.タイムアウト: | @Timeoutアノテーションを利用。处理に要する最大时间を定义します |
2.リトライ: | @Retryアノテーションを利用。处理に失败した际のリトライ(再试行)の动作を设定します |
3.フォールバック: | @Fallbackアノテーションを利用。处理に失败した际の代替の方法を提供(别メソッドの呼び出し)します |
4.隔ルクヘッド(隔壁): | これにより,高负荷时に単一の处理に负荷が集中してレスポンスが低下し,これを起因としたシステム全体テムの连锁的な障害を防ぎ ます |
5.サーキット・ブレーカー: | @CircuitBreakerアノテーションを利用。处理が缲り返して失败する场合,その处理呼び出しを自动的に即时に失败しるようにします |
6.非同期: | @异步アノテーションを利用。处理を非同期にします |
基本的に,上记のいずれかのポリシーを适用したい场合(复数の指定も可),実装するクラス,もしくはメソッドにアノテーションを付加するだけで设定できます。
1. タイムアウト(@Timeout)ポリシー
仮にタイムアウトウ设定を事により,处理の完了を待ち続けるのを防ぎます。 カーカー・スレッドが枯渇するなど,呼び出し元にも负荷をかけてしまいかねません。
复,复数のマイクロサービスを実装する际,もしくは外部サービスを呼び出すような场合,各サービス间の连携においてタイムアムトウ设定を。
@Timeout(400) // 接続タイムアウト値 400ms (0.4 sec)public Connection getConnectionForServiceA() { Connection conn = connectionService(); return conn;}
@Timeoutのアノテーションはクラス,もしくはメソッドレベルで付加できます。タイムアウトウ达値に场合,TimeoutExceptionが送出されます。
2. リトライ(@Retry)ポリシー
ようないネットワーク障害や,接続先からの返信が返ってこないような场合,@ Retryアノテーションを使用して,处理呼び出しを再试行できます。
リトライポリシーでは以下を构成できます。
パラメータ | 说明 |
---|---|
maxRetries: | 最大のリトライ回数 |
延迟: | リトライ间隔 |
delayUnit: | 延迟のユニット |
maxDuration: | 再试行を実行する最大期间 |
durationUnit: | 持续时间ユニット |
抖动: | 再试行遅延のランダムな変化(クロック信号のタイミング(もしくは周期)のズレ) |
jitterDelayUnit: | 抖动ユニット |
重试: | 再试行する失败(Exception,Error)を指定 |
流产: | 中止する失败(Exception,Error)を指定 |
@Retryアノテーションはクラスレベル,もしくはメソッドレベルで付加可能で,クラスに付加した场合,クラス内に存在する全メソッドに适用されます。 アノテーションを付加し,メソッドにも付加した场合は,メソッドで指定した设定が有效になります。
- 正常に处理が终了した场合,结果を正常に返します。
- 送出された例外をabortOnで指定した场合,スローされた例外を再送出します
- 送出された例外をretryOnで指定した场合,メソッド呼び出しが再试行されます
- それ以外の场合,送出された例外を再送出します
Fault,他のFault Toleranceのアノテーションと共に并用できます。
/**
* serviceA() メソッド呼び出しで、例外が送出された場合に、
* 例外が IOException でない場合は再試行します。
*/
@Retry(retryOn = Exception.class, abortOn = IOException.class)
public void invokeService() {
callServiceA();
}
/**
* 最大再試行回数は90、再試行を実行する最大期間は 1000 ミリ秒に設定
* 再試行の最大期間に達すると、最大再試行回数に達していない場合でも、再試行は実行されない。
*/
@Retry(maxRetries = 90, maxDuration= 1000)
public void serviceB() {
callServiceB();
}
/**
* クロック周波数のズレ(jitter)を 400ms と仮定した場合、-400ms 〜 400ms つまり
* 0 (delay - jitter) 〜 800ms (delay + jitter )の差で再試行が行われることが予想されます。
* 最大遅延が発生した場合を想定し、3200/800=4 で、最低試行回数は4回以上、
* 最大でも 10 回を超えない試行回数を設定します
*/
@Retry(delay = 400, maxDuration= 3200, jitter= 400, maxRetries = 10)
public Connection serviceA() {
return getConnectionForServiceA();
}
3. フォールバック(@Fallback)ポリシー
@Fallbackアノテーションはメソッはメソルで指定できます。
@Fallbackアノテーションは,単体もしくは他の故障容忍アノテーションと一绪に使用できます。
Reとえば,@ Retryが定义されている场合,リトライが最大试行回数を超えた场合にフォールバックの处理が実行されます。
Circ,@ CircuitBreakerが共に定义されている场合,メソッド呼び出しが失败した场合に直ちに呼び出されます。そしてサーキットがオープンしている场合は常に,フォールバック・メソッドが呼び出されます。
3.1 FallbackHandlerの実装によるフォールバックク处理の実装例
FallbackHandlerインタフェースを実装したFallbackHandlerのクラス(ServiceInvocationAFallbackHandler)を定义します。そしてhandleメソッド内で代替の处理を実装します。
ここでは,MicroProfile Configを利用してapp.serviceinvokeA.FallbackReplyMessageのプロパティ,もしくは环境変数などで定义した文字列を返信するように実装しています。
@Dependent
public class ServiceInvocationAFallbackHandler implements FallbackHandler<String> {
@ConfigProperty(name="app.serviceinvokeA.FallbackReplyMessage", defaultValue = "Unconfigured Default Reply")
private String replyString;
@Override
public String handle(ExecutionContext ec) {
return replyString;
}
}
下记の,BusinessLogicServiceBean#invokeServiceA()メソッドが呼び出されると,ここでは内部的にRuntimeExceptionが発生しますが3回处理の再试行します,全ての再试行に失败したのち,ServiceInvocationAFallbackHandler#handle()が呼び出さ れます。
@RequestScoped
public class BusinessLogicServiceBean {
// FallbackHandler の実装クラスを指定し @Fallback アノテーションを付加
// 最大のリトライ回数 (3回)を超えた場合、FallbackHandler の handle() メソッドが呼ばれる
@Retry(maxRetries = 3)
@Fallback(ServiceInvocationAFallbackHandler.class)
public String invokeServiceA() {
throw new RuntimeException("Connection failed");
return null;
}
}
3.2 fallbackMethodを指定したフォールバックク处理の実装例
@Fallbackアノテーション内で直接,代替で呼び出すメソッド名を记述します。
ここでは,fallbackForServiceB()替换为。
@RequestScoped
public class BusinessLogicServiceBean {
@Retry(maxRetries = 3)
@Fallback(fallbackMethod= "fallbackForServiceB")
public String invokeServiceB() {
counterForInvokingServiceB++;
return nameService();
}
@ConfigProperty(name="app.serviceinvokeB.FallbackReplyMessage", defaultValue = "Unconfigured Default Reply")
private String replyString;
private String fallbackForInvokeServiceB() {
return replyString;
}
4. バルクヘッド(@Bulkhead)ポリシー
Profileルクヘッド・パターンは,システムの一部のの防ぐために利用ぐために。MicroProfile
Bulkheadパターンは,大量に呼び出される可能成为あるコンポーネントや,高负荷时にレスポンス低下を招くようなサービスに対して适用すると效果的です。
@Bulkheadアノテーションはクラスレベル,もしくはメソッドレベルで付加可能で,クラスに付加した场合,クラス内に存在する全メソッドに适用されます。 アノテーションを付加し,メソッドにも付加した场合は,メソッドで指定した设定が有效になります。
バルクヘッドには下记の2种类の方法で设定可能です。
- スレッド・プールの分离:(@Asynchronousアノテーションと并用した场合) スレッド・プール内の待机中のキューサイズで最大同时リクエスト数を设定します。
- 分离フォの分离:(@ Asynchronousアノテーションと并用しない场合) 同时リクエスト数の设定のみが许可されます。
4.1スレッド・プールによる分离例
@异步アノテーションと并用した场合,スレッド・プールの分离が适用されます。下记の例では,最大で5つの同时リクエストが许可され,8つのリクエストが停キューで保持されます。
// 最大5つの同時リクエストが許可され、最大 8つのリクエストが待機キューで許可される
@Asynchronous
@Bulkhead(value = 5, waitingTaskQueue = 8)
public Future<Connection> invokeServiceA() {
Connection conn = null;
counterForInvokingServiceA++;
conn = connectionService();
return CompletableFuture.completedFuture(conn);
}
4.2セマフォによる分离例
@asynchronousアノテーションを并用しない场合は,単に同时リクエスト数を定义します。
@Bulkhead(5) // 最大5つの同時要求が許可されます
public Connection invokeServiceA() {
Connection conn = null;
counterForInvokingServiceA++;
conn = connectionService();
return conn;
}
5. サーキット・ブレーカー(@CircuitBreaker)ポリシー
もしくはーキット・ブレーカーは,障害のあるサービスに対して缲り返しの呼び出しを防いで,障害のあるサービスもしくはAPI呼び出しで直ちに失败するようにします。 の时间が経过するまでそのサービスへの呼び出しは试行されません。
@CircuitBreakerアノテーションはクラスレベル,もしくはメソッドレベルで付加可能で,クラスに付加した场合,クラス内に存在する全メソッドに适用されます。メソッドに付加した场合,指定したメソッドだけが対象になります。 アノテーションを付加し,メソッドにも付加した场合は,メソッドで指定した设定が有效になります。
サーキットブレーカーの3つの状態
クローズド: (通常时)
通常情况下,サーキットブレーカーじて闭各います。サーキットブレーカーはー 。
オープン: (障害発生时)
るーキットブレーカーがーいが场合,サーキットブレーカーで动作でいるサービスへの呼び出しは,CircuitBreakerOpenExceptionで直ちに失败ちに。
ハーフ・オープン: (障害复旧の确认中)
ハーフオープン状态では,サービス呼び出しの试行が始まります(设定可能な数)。仮にいずれかの呼び出しで障害が発生した场合,再度サーキットブレーカはオープン状态に戻ります。 カーカーはクローズド状态に移行します。
サーキット・ブレーカの実装例1
@CircuitBreaker(successThreshold = 10, requestVolumeThreshold = 4, failureRatio=0.5, delay = 1000)
public Connection serviceA() {
Connection conn = null;
counterForInvokingServiceA++;
conn = connectionService();
return conn;
}
パラメータ | 说明 |
---|---|
requestVolumeThreshold: | 障ーットブレーカーが「クローズ」のときに使用するローリングウィンドウ(障害比率を计算するための分母の数)のサイズ |
故障率: | をーットブレーカーを「オープン」にするための,ローリングウィンドウ内の障害比率 |
成功阈值: | ハーットブレーカーが「ハーフ・オープン」の时,クローズドに移行するための试行回数 |
delayおよびdelay单位: | をーキットブレーカーを「オープン」にしつづける时间 |
上记では,requestVolumeThresholdで指定したローリングウィングウィ数ドウ4回の连続した呼び出し中に2回(4 x 0.5)の障害が発生すると,サーキットが「オープン」します。サーキットは1,000ミリ秒间「オープン」の ハ,その后「ハーフ・オープン」に移ります。「ハーフ・オープン」で10回呼び出しが成功すると,サーキットは再は「クローズ」になります。
リクエスト1-成功
リクエスト2-失敗
リクエスト3-成功
リクエスト4-成功
リクエスト5-失敗
リクエスト6-CircuitBreakerOpenException
上记のリクエストの场合,最后の4つのリクエストのうち2つが失败し,failureRatioが0.5に达するため,「リクエスト5」でサーキットが「オープン」になりCircuitBreakerOpenExceptionが送出されます。
成功/失敗とみなす例外定義を追加
failOnパラメーターとskipOnパラメーターは,サーキットブレーカーを「オープン」にするか否かを决定するため,どの例外を失败と见なすかを定义するために使用します。
@CircuitBreaker(successThreshold = 10, requestVolumeThreshold = 4, failureRatio=0.5, delay = 1000,failOn = {ExceptionA.class, ExceptionB.class}, skipOn = ExceptionBSub.class))
public Connection serviceA() {
Connection conn = null;
counterForInvokingServiceA++;
conn = connectionService();
return conn;
}
failOnに指定した例外が発生した场合は,失败とみなします
skipOnに指定した例外が発生した场合は,成功とみなします
6. 非同期(@Asynchronous)ポリシー
Fault Tolerance の主な機能は 建筑 に記述されているように、上記 1-5 までにあげた機能です。そこで、非同期処理は直接 Fault Tolerance と関連するわけではありません。しかし、分散処理において非同期処理はとても重要で Fault Tolerance の各種機能と組み合わせる事により、より有効的に働くため仕様内に取り込まれました。
如上所述,容错规范将重点放在以下方面:
- 超时:定义超时时间
- 重试:定义何时重试的条件
- 后备:为执行失败提供替代解决方案。
- CircuitBreaker:通过自动执行失败来提供一种快速的失败方法,以防止系统过载以及客户端无限期的等待或超时。
- 隔板:隔离系统的一部分故障,而系统的其余部分仍然可以运行。
@Asynchronousアノテーションはクラスレベル,もしくはメソッドレベルで付加可能で,クラスに付加した场合,クラス内に存在する全メソッドに适用されます。メソッドに付加した场合,指定したメソッドだけが対象になります。クラス アノテーションを付加し,メソッドにも付加した场合は,メソッドで指定した设定が有效になります。
@Asynchronousアノテーションが付加されたメソッドが呼び出されるとされる,すぐにFutureもしくはCompletionStageを返します。残りのメソッド本体の处理は别スレッレ行ドで実。 正しい値を持ちません。仮に处理中に例外が発生した场合は,FutureまたはCompletionStageはその例外で终了します。
处理が正常に完了した场合,FutureもしくはCompletionStageは戻り値(それ自体がFutureまたはCompletionStage)を返します。
@Asynchronous
public CompletionStage <Connection> serviceA(){
Connection conn = null;
counterForInvokingServiceA ++;
conn = connectionService();
return CompletableFuture.completedFuture(conn);
}
上记の例では,serviceAメソッドへの呼び出しが非同时处理になります。serviceAの呼び出しはCompletionStageを返し,メソッド本体の実行は别スレッドで実行されます。
注意:
CDIのRequestScopeから@Asynchronousを呼び出す场合,非同时メソッド呼び出し中RequestScopeティブでなければなりませんアクティブでなければなりません。 场合い场合,FaultToleranceDefinitionExceptionが発生します。
ソースコードに記載した設定値の上書き方法
各节で确认したように,Fault Toleranceのaultリシーは一部を除いてほとんどの场合,アノテーションを使用して适用できます。
Microースコードの実装后,仮にアノテーションショ装した値を変更したい场合は,MicroProfile Configを使用して设定値を上书きすることもできます。
アノテーション内のパラメーターは,次の命名规则を使用して,设定プロパティーで上书きできます:
<classname>/<methodname>/<annotation>/<parameter>
outとえば,ある特定のメソッドで指定したTimeoutやRetryのアノテーションで指定したパラメータを外部で上书き设定したい场合,MicroProfile Configで下记のように记述します。
com.yoshio3.FaultToleranceService.resilient.ResilienceController/checkTimeout/Timeout/value=2000
com.yoshio3.FaultToleranceService.resilient.ResilienceController/checkTimeout/Retry/maxDuration=3000
仮に,クラス全体に适用したい场合は下记のように,メソッド名の部分を削除してクラス全体に适用することもできます。
com.yoshio3.FaultToleranceService.resilient.ResilienceController/Timeout/value=2000
com.yoshio3.FaultToleranceService.resilient.ResilienceController/Retry/maxDuration=3000
そして,プロジェクト内の全コードに対して相同ルールを适用したい场合は,アノテーションとパラメータ设定だけを记することもできます。
Timeout/value=2000
Retry/maxDuration=3000
さいごに
Micro,MicroProfile Fault Toleranceを利用して耐障害性を高めるアプリケーションを构筑するためのコードを确认しました。次は,Fault Toleranceを利用したア障リケーションショ际を実构筑し,Azure上で耐障害性を 复数のサービスを连携をしてみたいと思います。