はじめに Circuit Breakerの紹介記事を先に読むことを推奨します。 チャネルゲートウェイにCircuitBreakerを適用する チャネルゲートウェイサーバは、LINEの多様なサーバの機能をCP(Contents Provider)に提供する役割を担っています。そのため、チャネルゲートウェイサーバは接続されているサーバに大きく影響されます。なお、そうした影響はチャネルゲートウェイサーバ全体に容易に拡散します。 この問題の解決に悩んでいたところ、CircuitBreakerに関する内容を聞きました。特定のサーバに障害が発生した場合、CircuitBreakerがそれを検知してそのサーバに投げられるリクエストを遮断すれば、問題を十分解決できると思いました。そのため、チャネルゲートウェイにCircuitBreakerを適用することを決めました。 チャネルゲートウェイ用のCircuitBreakerを直接実装することもできましたが、Armeriaにすでに見事なCircuit Breakerが実装されていました。ArmeriaのCircuitBreakerは、様々なオプションをニーズに合わせて設定し、CircuitBreakerBuilderで実装されたCircuitBreakerオブジェクトを得ることができます。このオブジェクトによってチャネルゲートウェイに合わせてカスタマイズできるようになっているので、簡単に適用することができました。 CircuitBreakerのアノテーションの使用 talk-channel-gatewayソースコードにおいてCircuitBreakerは、@CircuitBreakableアノテーションを使用して適用できます。 @CircuitBreakable(CircuitBreakerGroup.HBASE_CLIENT_USER_SETTINGS) public ChannelSettings findBy(String mid) { ... } 上記のように適用した場合、findBy()メソッドが呼び出される度に成功/失敗を監視し、その結果によってCircuitBreakerが開閉します。HBASE_CLIENT_USER_SETTINGSはCircuitBreakerで束ねるグループを指定するもので、各メソッドの失敗率を計算する際もグループ全体の呼び出し回数に対する失敗回数で計算し、CircuitBreakerの開閉時も一緒に開閉します。 CircuitBreakerの設定は、CircuitBreakerGroupというenumオブジェクトで次のように設定できます。 public enum CircuitBreakerGroup implements ExceptionFilter { SAMPLE_DEFAULT { }, SAMPLE_API { @Override protected ExceptionFilter exceptionFilter() { return cause -> !(cause instanceof AuthenticationException || cause instanceof ApiPermissionException || cause instanceof ImproperRequestException); } }, HBASE_CLIENT_CHANNEL_MATRIX { }, HBASE_CLIENT_USER_SETTINGS { }; protected ExceptionFilter exceptionFilter() { return cause -> true; } public CircuitBreaker circuitBreaker(CircuitBreakerListener listener) { return new `CircuitBreakerBuilder`(name()).exceptionFilter(exceptionFilter()) .listener(listener) .build(); } @Override public boolean shouldDealWith(Throwable throwable) throws Exception { return exceptionFilter().shouldDealWith(throwable); } } チャネルゲートウェイではExceptionFilterをカスタマイズして使用しました。それ以外のオプションは、Armeriaのデフォルトオプションをそのまま使用しました。もし、他のオプションを変更して使いたい場合は、circuitBreaker()メソッドを修正して使用できるでしょう。 Armeriaでは、どんなものであってもExceptionが発生した場合は基本的に失敗とみなすようになっています。しかし、チャネルゲートウェイでは、権限がない場合などをExceptionとして処理して返すので、それを区分する必要がありました。そのため、ExceptionFilterをカスタマイズして使用しました。そして、CircuitBreakerのステータスが変わる度にログを蓄積できるように、チャネルゲートウェイのためのListenerも追加しました。 アノテーションに適用するグループはenumオブジェクトで指定でき、enumオブジェクトを実装部においてグループごとに設定を変えられるようにしました。 CircuitBreakerにおけるproceed()の実装 Aspect オブジェクトのproceed()コードは以下のとおりです。 public class CircuitBreakerAspect implements Ordered { private final Map<CircuitBreakerGroup, CircuitBreaker> circuitBreakers = new (…)
↧