Hystrixでレジリエンスのある マイクロサービスを構築する ·...

17
ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018 26 //the leading edge/ イクロサービス・アーキテクチャに基づいてアプリケーションを構築する場合や、モノリシックなシステムを 複数のサービスに分割する場合、次に挙げるような、よくあるいくつかの課題に直面します。 いずれかのサブシステムで障害や遅延が起きたときに、クライアントから見たシステム全体の可用性を確保す るためにはどのようにすればよいか。 クライアントのリクエストに応じて処理するサブシステムを複数使用できる場合、どのようなパターンでサブシ ステムを切り替えればよいか。たとえば、ストアド・プロシージャの代わりにマイクロサービスを使うことにするが、 移行期間中はストアド・プロシージャを呼び出す機能を保持する必要がある場合はどうすればよいか。あるいは、 データベースから最新のデータを取得したいが、データベースが遅い場合、キャッシュ・サービスからの回答を どのように使えばよいか。 負荷が高すぎるサブシステムや、遅延が発生しているサブシステムをリアルタイムで監視するためには、どのよ うにすればよいか。 サブシステムを急激な負荷上昇から自動復旧させるには、どのようにすればよいか。 API を開放して他のシステムから使用できるようにしつつ、システムのパフォーマンスに悪影響が及ばないよう にするためには、どのようにすればよいか。 本記事では、Netflix が開発したオープンソース・ライブラリである Hystrix を使用して、上記のようなよくある課 題を解決する方法を示します。GitHub に記載されている説明によると、Hystrix は「耐遅延、耐障害ライブラリ」 であり、「リモート・システム、サービス、サードパーティ製ライブラリに対するアクセス・ポイントを隔離し、連 鎖障害を防止して、障害が避けられない複雑な分散システムでレジリエンスを実現する」ために設計されています。 Hystrixでレジリエンスのある マイクロサービスを構築する 分散アプリケーションでの遅延や障害に対処する便利なNetflix製ライブラリ HENRY NAFTULIN

Transcript of Hystrixでレジリエンスのある マイクロサービスを構築する ·...

Page 1: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

26

//the leading edge/

マイクロサービス・アーキテクチャに基づいてアプリケーションを構築する場合や、モノリシックなシステムを

複数のサービスに分割する場合、次に挙げるような、よくあるいくつかの課題に直面します。 ■ いずれかのサブシステムで障害や遅延が起きたときに、クライアントから見たシステム全体の可用性を確保す

るためにはどのようにすればよいか。 ■ クライアントのリクエストに応じて処理するサブシステムを複数使用できる場合、どのようなパターンでサブシ

ステムを切り替えればよいか。たとえば、ストアド・プロシージャの代わりにマイクロサービスを使うことにするが、

移行期間中はストアド・プロシージャを呼び出す機能を保持する必要がある場合はどうすればよいか。あるいは、

データベースから最新のデータを取得したいが、データベースが遅い場合、キャッシュ・サービスからの回答を

どのように使えばよいか。 ■ 負荷が高すぎるサブシステムや、遅延が発生しているサブシステムをリアルタイムで監視するためには、どのよ

うにすればよいか。 ■ サブシステムを急激な負荷上昇から自動復旧させるには、どのようにすればよいか。 ■ APIを開放して他のシステムから使用できるようにしつつ、システムのパフォーマンスに悪影響が及ばないよう

にするためには、どのようにすればよいか。

本記事では、Netflix が開発したオープンソース・ライブラリであるHystrixを使用して、上記のようなよくある課

題を解決する方法を示します。GitHubに記載されている説明によると、Hystrix は「耐遅延、耐障害ライブラリ」

であり、「リモート・システム、サービス、サードパーティ製ライブラリに対するアクセス・ポイントを隔離し、連

鎖障害を防止して、障害が避けられない複雑な分散システムでレジリエンスを実現する」ために設計されています。

Hystrixでレジリエンスのある マイクロサービスを構築する分散アプリケーションでの遅延や障害に対処する便利なNetflix製ライブラリ

HENRY NAFTULIN

Page 2: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

27

//the leading edge/

本記事では、Spring Boot およびMavenのテクノロジーを使用するため、これらの知識が必要になります。

準備株式仲介口座の保有株式を表示するマイクロサービスを書く必要があるとします。具体的には、ユーザー名を指

定すると、そのユーザーが保有する株式数と、その株式価格および保有価値(株式数に株式価格を掛けたもの)

を返すものとします。

これを実現するために、同僚が作成したマイクロサービスを使う必要があります。このマイクロサービスは、

株式のティッカー・シンボルを受け取り、その価格を返します。まずは、株式価格を返す価格マイクロサービス

を見てみます(リスト1)。

リスト1:株式価格を返す単純なサービス@RestControllerpublic class TickerServiceController { ...

@RequestMapping(value = "/getTickerPrice/{ticker}", method = RequestMethod.GET) public Double getTickerPrice(@PathVariable String ticker){ Random r = new Random();

long processingTime = (long) (r.nextGaussian() * stdDevProcessingTimeInMillis + meanProcessingTimeInMillis);

try { Thread.sleep(processingTime); } catch (InterruptedException e) { LOGGER.error(e.getMessage(), e); }

Page 3: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

28

//the leading edge/

if (r.nextDouble() < (outOfServiceRate/100.0)) { throw new RuntimeException("Service not available"); } return getTickerPriceFromExchanges(ticker); }}

とても単純なサービスです。任意の名前に対して、getTickerPriceFromExchanges メソッドで生成される価格を返しています。このサービスでは、サービスの失敗率と、データストアからのデータ取得に要する時間という2つ

の重要な動作をシミュレートしています。実際には、予期せぬ内部障害(データストアの停止など)が原因でこの

サブシステムが動作しなくなったとき、それを使用するアプリケーションで障害が発生する可能性があります。

次に、保有株式サービスを見てみます。このサービスでは、Springの restTemplate を使用してリクエスト

を価格マイクロサービスに送信し、結果を返しています。リスト2をご覧ください。

リスト2:Springの restTemplateを使用して価格をリクエストするサービス@Servicepublic class TickerPriceRetrieverService { public Double getLatestPrice(String ticker, RestTemplate restTemplate) throws Exception { Double price = restTemplate.exchange( "http://localhost:8098/getTickerPrice/{ticker}" , HttpMethod.GET , null , new ParameterizedTypeReference<Double>() {} , ticker).getBody(); return price; }}

Page 4: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

29

//the leading edge/

このサービスは、WebアプリケーションのgetHoldings エンドポイントを通じて公開しています。リスト3をご覧

ください。このリストには、複数のクラスが含まれています。

リスト3:保有株式サービスのエンドポイントpublic interface PriceDelegate { Double getLatestPrice(String ticker) throws Exception;}

@Servicepublic class NonHystrixDelegate implements PriceDelegate { private TickerPriceRetrieverService priceService; private final RestTemplate restTemplate; public NonHystrixDelegate(TickerPriceRetrieverService priceService){ this.priceService = priceService; restTemplate = new RestTemplate(); }

@Override public Double getLatestPrice(String ticker) throws Exception { return priceService.getLatestPrice(ticker, restTemplate); } }

@RestControllerpublic class HoldingsServiceController {... private final NonHystrixDelegate nonHystrix;

Page 5: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

30

//the leading edge/

private final HystrixDelegate hystrix; ...

@RequestMapping(value = "/getHoldings/{customer}", method = RequestMethod.GET) public List<Holding> getHoldings( @PathVariable String customer) throws Exception { List<Holding> holdings = getHoldings(); holdings.stream().forEach(h -> { try { h.setPrice(nonHystrix.getLatestPrice(h.getTicker())); } catch (Exception e) { LOGGER.error(e.getMessage(),e); } }); return holdings; }

private List<Holding> getHoldings() { return Arrays.asList(new Holding("IBM", 100.0)); }}

この実装をテストします。ここでは、Apache の HTTPサーバー・テスト・ツールであるabを使ってソリューショ

ンの負荷テストを行います。abツールは保有株式サービスを呼び出し、保有株式サービスは価格サービスを呼び

出します。価格サービスの動作にかかわらず、保有株式サービスがレジリエントであることが興味深いと思います。

Page 6: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

31

//the leading edge/

それでは、アプリケーションのテストを行います。ここでは、10のクライアントによる合計 500 件のリクエ

ストをシミュレートします。まずは、価格サービスの応答に100ミリ秒かかる場合です(テスト#1)。次に、価格サー

ビスの応答に1,000ミリ秒かかる場合です(テスト#2)。そして最後に、価格サービスがリクエストを取得するま

でに1,000ミリ秒かかり、15%の確率でサービスが停止する場合です(テスト#3)。

テストは、たとえば次のようにして実行します。

ab -n 500 -c 10 http://localhost:8088/getHoldings/Jake

表1に、テストの結果を示します。

予想どおり、保有株式サービスのリクエスト処理時間は、使用する価格マイクロサービスが結果を取得する

ためにかかる時間と、わずかに増加するオーバーヘッドに直接的に依存しています。

サービス停止率を設定したところ、リクエストの一部が失敗しました。失敗したリクエストの割合は、想定

される失敗率の15%をわずかに上回りました。保有株式サービスの処理時間とエラー率は、価格マイクロサービ

スに直接的に依存します。そのため、この実装は、使用するサブシステムの動作に対してレジリエントでないと言

えます。

表1:abを3回実行してアプリをテストした結果

テスト#1 テスト#2 テスト#3リクエスト数 500 500 500

価格サービスの平均処理時間(ミリ秒) 100 1,000 1,000

価格サービスのサービス停止率 0% 0% 15%

価格サービスの処理時間の標準偏差(ミリ秒) 20 200 200

テストに要した時間(秒) 5.31 50.666 51.052

失敗したリクエストの数 0 0 85

1秒あたりのリクエスト数 94.00 9.87 9.80

保有株式サービスの応答時間の50パーセンタイル(ミリ秒) 105 1,011 1,010

保有株式サービスの応答時間の95パーセンタイル(ミリ秒) 138 1,321 1,334

Page 7: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

32

//the leading edge/

Hystrix の追加ここで要件変更が発生し、価格マイクロサービスを待機する時間を最大1,200ミリ秒に制限する必要があるとし

ます。価格サービスから最新の価格を取得できない場合は、ローカルにキャッシュされた価格を返します。こういっ

た使用例は、現実的です。使用するサービスが結果を返すまで永遠に待ち続けたくはないからです(また、予想

最大損失額や純資産などを知りたい場合、価値がまったくわからないよりも、ある程度の資産価格の見積もり

がある方がずっとよいでしょう)。

タイムアウトの仕組みを導入してリクエストを失敗させるコードを書くことも可能ですが、はるかに望まし

いのは、Hystrix ライブラリを使用する方法です。ここでは、Hystrixを使用して応答時間を監視し、あらかじめ

設定したしきい値を超えた場合、フェイルオーバーを行います。これを行うために、後述のリストに示すように、

Hystrixコマンドを作成してインスタンス化しています。後ほど説明しますが、Hystrixを使うことで、実装がシン

プルになります。また、ニーズに合わせて調整することや、価格マイクロサービスとの相互作用を監視することも

できます。

Hystrixを使用するためには、まず、Hystrix自体と、Hystrix が内部的に使用しているrxjava ライブラリへの依存性をプロジェクトにいくつか追加する必要があります。

<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.2.0</version></dependency>

<!-- Hystrix が使用 --><dependency> <groupId>io.reactivex</groupId> <artifactId>rxjava</artifactId> <version>1.2.0</version></dependency>

Page 8: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

33

//the leading edge/

続いて、リスト4に示すように、Hystrixコマンドを定義する必要があります。このコマンドでは、株式のティッカー・シンボルを指定して、その価格を取得します。

リスト4:Hystrixコマンドの定義static class PriceCommand extends HystrixCommand<Double> { private final TickerPriceRetrieverService priceDelegate; private final String ticker; private final RestTemplate restTemplate; public PriceCommand(TickerPriceRetrieverService priceDelegate, String ticker, RestTemplate restTemplate, HystrixCommand.Setter config) { super(config); this.priceDelegate = priceDelegate; this.ticker = ticker; this.restTemplate = restTemplate; } @Override public Double run() throws Exception { return priceDelegate.getLatestPrice(ticker, restTemplate); } @Override public Double getFallback() { return Cache.getPrice(ticker); }}

Hystrixコマンドを記述するときは、通常、run とgetFallback という2つのメソッドをオーバーライドします。runメソッドはHystrixコマンドの主役で、使用するサブシステムやAPIから結果を取得するロジックを実装します。こ

Page 9: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

34

//the leading edge/

の例のコードはとてもシンプルで、先ほど記述した既存のAPIに実装を委譲し、ティッカー価格を取得しています

(リスト2参照)。ここで、タイムアウトについて心配する必要はありません。タイムアウト(および他の構成パラメータ)は、コマンドの初期化時に使用する構成オブジェクトによって設定されます。getFallback メソッドをオーバーライドしているのは、タイムアウトや、使用するサービスでエラーがスローされたことによってrun メソッドが失敗した場合に、別の結果を使用するからです。今回の例では、フォールバックとして、キャッシュされた価格を使

用することになります。getFallback メソッドをオーバーライドしなかった場合、タイムアウト、または価格デリゲートが受け取ったエラーがコール元のコードに伝播されます。

コマンドはステートフルで、再利用できません。そのため、リクエストのたびにインスタンス化する必要があ

ります。今回の例では、特定の構成でインスタンス化しますが、この点については後ほど説明します。リスト5は、Hystrixコマンドをインスタンス化するコードです。

リスト5:Hystrixコマンドのインスタンス化@Servicepublic class HystrixDelegate implements PriceDelegate { ... HystrixCommand.Setter config; public HystrixDelegate( TickerPriceRetrieverService priceDelegateImpl) { this.priceDelegateImpl = priceDelegateImpl; restTemplate = new RestTemplate(); config = HystrixCommand .Setter .withGroupKey(HystrixCommandGroupKey .Factory.asKey("PriceCommand")); HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter(); commandProperties

Page 10: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

35

//the leading edge/

.withExecutionIsolationThreadTimeoutInMilliseconds(1200); config.andCommandPropertiesDefaults(commandProperties); config.andThreadPoolPropertiesDefaults( HystrixThreadPoolProperties.Setter() .withMaxQueueSize(-1) .withCoreSize(15)); } @Override public Double getLatestPrice(String ticker) throws Exception { PriceCommand pc = new PriceCommand(priceDelegateImpl, ticker, restTemplate, config); Future<Double> pcFuture = pc.queue(); return pcFuture.get(); }}

ここで行いたいことは、デフォルトのHystrix 構成のオーバーライドです。具体的には、処理時間が1,200ミリ

秒を超えた場合、価格サービスに送信した、元のリクエストを破棄するようにHystrixを構成します。その場合、

Hystrix は getFallback メソッドの戻り値を返します。 Hystrix は、内部的にスレッド・プールをインスタンス化して使用します。ユーザーが定義した各コマンド・タ

イプには、10 個のスレッドをプールしたスレッド・プールが割り当てられます。今回の例では、PriceCommandというHystrixコマンドを1つだけ使っています。そのため、デフォルトでは、10 個のスレッドがプールされた1

つのスレッド・プールでこのコマンドが実行されます。デフォルトの設定を使用するとどうなるかは後述しますが、

ここでは、Hystrix のドキュメントを参照して、スレッド・プールのサイズを適切な値に設定します。

Page 11: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

36

//the leading edge/

価格サービスを呼び出す際に使うスレッド・プールのサイズを設定するために、ドキュメントに記載されてい

る次の計算式を使います。

正常なピーク時における1秒あたりの最大リクエスト数 × 遅延の 99 パーセンタイル (秒) + 多少の余裕

最適なスレッド数を計算するために、表1のテスト結果で、「1秒あたりのリクエスト数」と「保有株式サービスの応答時間の95パーセンタイル」の行を確認します。価格サービスの応答が高速なときは、1秒あたり94件のリ

クエストを受け取っています。この値を先ほどの計算式に当てはめ、0.138 秒(95パーセンタイル)を掛けると、

スレッド・プールのサイズはおよそ12スレッドとなります。サービスの応答が遅い場合の計算式の各値は、1秒あ

たり9.87件のリクエストに1.321秒を掛けたものとなり、スレッド・プールのサイズはおよそ13スレッドとなります。

そこで、多少の余裕を持たせ、15スレッドを設定してスレッ

ド・プールを構成します。

Hystrixを使用するメリットの1つに、Hystrix API が

Hystrixコマンドの実行に関する統計情報を保持している

ことが挙げられます。この統計情報には、コマンドが結

果を処理した時間、コマンドがタイムアウトしたかどうか、

リクエストに応じて処理するための十分なスレッドがス

レッド・プール内に存在していたか、などが含まれています。

この統計情報を使うと、リアルタイム監視が可能になるとともに、Hystrixコマンドの動作を制御できます。

Hystrixでコマンドを作成すると、コマンドの失敗を監視するサーキット・ブレーカーがデフォルトで構成されます。

今回の例では、次の場合にコマンドが失敗します。 ■ 1,200ミリ秒を超えてもティッカー価格が返されない(タイムアウト) ■ コマンドが例外をスローした ■ 価格サービスが停止している

一定期間内に一定回数の失敗が発生(これも変更可能な構成値です)したとき、Hystrix のサーキット・ブレー

カーがクローズ状態からオープン状態に切り替わります。デフォルトの状態はクローズ状態で、このとき、Hystrix

のサーキット・ブレーカーはターゲット・システムにリクエストを送信できます。オープン状態は失敗の後に遷

移する状態で、しきい値の違反が発生しています。この場合、Hystrix は使用するシステムを呼び出すことなく、

Hystrixを使用することによって生まれる別の利点は、システムの動作状況を報告するリアルタイム監視を簡単に追加できることです。

Page 12: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

37

//the leading edge/

getFallback メソッドの戻し値を返します。 デフォルトでは、直近の一定時間(デフォルトは10秒)内に、リクエストが20回失敗するか、またはその

時間内に50%を超えるリクエストが失敗したとき、オープン状態に切り替わります。表2に、Hystrix 実装に対して先ほどと同様のabテストを実行した結果を示します。

価格マイクロサービスが高速である(つまり、平均100ミリ秒以内にリクエストを処理するように構成している)

場合、非Hystrix 実装とよく似た結果が出ています。Hystrix によるリクエスト処理のため、時間が少し長くなって

いますが、今回の目的を踏まえれば、この増加時間は大したものではありません。

価格サービスのリクエスト処理が平均1秒かかるように構成した場合、Hystrixでは1,200ミリ秒より長い時

間がかかるリクエストをタイムアウトさせます。その場合、フォールバック・ソリューションが使われます。サーキッ

ト・ブレーカーがオープン状態になると、しばらくの間リクエストが価格サービスに送信されなくなり、Hystrix が

サーキットをクローズ状態に戻すまで、フォールバック・ソリューションが使われます。

価格サービスを停止すると、この動作をはっきりと確認できます。最初、アプリケーションはサービスにアク

セスしようとしますが、サーキット・ブレーカーがオープン状態になると、使用するサービスにアクセスしようとす

表2:Hystrixを使用した場合のテスト結果

テスト#1 テスト#2 テスト#3 テスト#4リクエスト数 500 500 500 500

価格サービスの平均処理時間(ミリ秒) 100 1,000 1,000 1,000

サービス停止率 0% 0% 15% サービス停止

価格サービスの処理時間の標準偏差(ミリ秒) 20 200 200 200

リクエストの最大許容時間(ミリ秒) 1,200 1,200 1,200 1,200

テストに要した時間(秒) 5.401 49.559 49.869 4.723

失敗したリクエストの数 0 0 85 0

1秒あたりのリクエスト数 92.58 9.87 10.3 105.87

保有株式サービスの応答時間の50パーセンタイル(ミリ秒) 108 997 1,001 36

保有株式サービスの応答時間の95パーセンタイル(ミリ秒) 140 1,207 1,207 109

フォールバック・メソッドを使用したリクエスト数 0 83 170 500

Page 13: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

38

//the leading edge/

ることさえなくなります。特にこの例では、価格リクエストが、15%のリクエストが失敗する列よりも、概してか

なり速くなっている(50パーセンタイルで36ミリ秒)ことがわかります。

この動作は、サーキット・ブレーカーを使用するHystrixコマンドのおもな特徴を浮き彫りにしています。 ■ 使用するライブラリまたはサービスが応答しない場合、あるいはエラーをスローした場合、フォールバック値を

返す。 ■ 要件として指定しない限り、使用するライブラリで発生したエラーはクライアントに伝播されない。 ■ ライブラリまたは使用するサービスが復旧するための時間を与える。サーキット・ブレーカーがオープン状態に

なると、ほとんどのリクエストは使用するサービスに到達しない。使用するシステムが復旧したかどうかを確認

するために、プローブ・リクエストが時々送信される。プローブ・リクエストが成功した場合、使用するシステ

ムは健全であると見なされ、リクエストはそのシステムを使用するようにルーティングされる。

監視Hystrixを使用することによって生まれる別の利点は、システムの動作状況を報告するリアルタイム監視を簡単に

追加できることです。これを行うためには、次のようにして、Hystrix の統計情報を生成するライブラリを保有株

式プロジェクトに追加する必要があります。

<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-metrics-event-stream</artifactId> <version>1.2.0</version></dependency>

続いて、リスト6に示すようにストリーム・サーブレットを構成します。

リスト6:リアルタイム統計情報を取得するストリーム・サーブレットの構成@Configurationpublic class HystrixStreamServletDefinition {

@Bean(name = "hystrixRegistrationBean") public ServletRegistrationBean servletRegistrationBean() {

Page 14: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

39

//the leading edge/

ServletRegistrationBean registration = new ServletRegistrationBean( new HystrixMetricsStreamServlet(),"/hystrix.stream"); registration.setName("hystrixServlet"); registration.setLoadOnStartup(1); return registration; }}

以上です。次は、監視アプリケーションを作成する必要があります。保有株式サービスのパフォーマンスに影響

を与えたくなかったため、監視アプリケーションは別のサービスにすることにしました。実際にはおそらく、適切

な認証や認可を追加して同様のサービスを構成し、すべてのHystrix ストリームを1か所で監視できるようにする

でしょう。

完全な設定をダウンロードしてスタンドアロンの監視サービスを開始することもできますが、Spring Bootで

そのサービスを作成するのも簡単です。これを行うためには、Spring Boot に次のライブラリを準備する必要があ

ります。

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.5.RELEASE</version></dependency>

リスト7に、監視アプリケーションの構成方法を示します。

リスト7:監視アプリケーションの構成@SpringBootApplication@EnableHystrixDashboardpublic class HystrixMonitorApplication {

public static void main(String[] args) {

Page 15: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

40

//the leading edge/

SpringApplication.run(HystrixMonitorApplication.class, args); }}

ここでのポイントは、Hystrixダッシュボードを有効にするアノテーションです。サービスを実行し、図1に示すように、Hystrixダッシュボード・アプリケーション(http://localhost:8078/hystrix/)にストリームのURL(http://

localhost:8088/hystrix.stream)を貼り付けます。

図 2に、テストの1つを再実行した際の監視アプリケーションのスクリーンショットを示します。図 2の黄色い丸はリクエストの数量と健全性を、青い線はリクエストの速度を示しています。ここでは、期間中に成功し

たリクエストは66 件、タイムアウトは16回、例外は12回で、報告された期間のコマンド・エラー率は24%でし

た。また、Hystrixコマンドは、1秒あたり9.8 件の速度でリクエスト処理を行いました。

Hystrix による監視では、依存するシステムを監視する際に便利な情報が提供されます。筆者の経験によれ

ば、ダッシュボードを実行することでHystrix の仕組みへの理解が深まります。ダッシュボードは、調整すべきパ

図1:Hystrixダッシュボード・アプリケーション

Page 16: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

41

//the leading edge/

ラメータを判別する際にもとても役立ちます。

例を挙げます。Hystrixでのデフォルトのスレッド・プール・サイズである10スレッドで構成されたサンプル・

アプリケーションをしばらく実行してみたところ、クライアントへの応答が予想よりもかなり高速で返されていま

した。このときは、リクエストを処理するためのスレッドが十分でなかったため、リクエストの失敗がエラーとし

てカウントされ、しばらくしてHystrix のサーキット・ブレーカーがオープン状態になっていたことになります。サー

キット・ブレーカーがオープン状態になると、フォールバック応答がクライアントに返されました。この応答は、

価格サービスからのものよりもはるかに高速でした。

また、Hystrixダッシュボードの実行中に、リクエストの送信後間もなくサーキット・ブレーカーがオープン状

態になったことと、スレッド・プール拒否数が増加したことも確認しました。前述のように、Hystrix が提供する

計算式を使用してスレッド・プール・サイズを調整すると、スレッド・プールで拒否が発生することがなくなり、テ

ストは想定どおり動作するようになりました。

図2:監視アプリのスクリーンショット

Page 17: Hystrixでレジリエンスのある マイクロサービスを構築する · 本記事では、Spring BootおよびMavenのテクノロジーを使用するため、これらの知識が必要になります。

ORACLE.COM/JAVAMAGAZINE //////////////////// SEPTEMBER/OCTOBER 2018

42

//the leading edge/

まとめ本記事では、現実に即した簡単な例でHystrix の使い方を説明し、障害が起きてもアプリケーションの可用性を

確保する方法を紹介しました。リアルタイムに価格を得ることが好ましいものの、キャッシュされた価格にフォー

ルバックしても構わないというようなシステムの好例です。

Hystrix は、システムのレジリエンスを高める際に役立つ有用なライブラリであるため、多くの企業で使用さ

れています。今回の例を通じて、Hystrix は、簡単に使うことができ、大きなメリットをもたらすことがおわかりい

ただけたかと思います。</article>

Henry Naftulin:15年以上にわたってJava EE 分散システムの設計に携わる。現在は、米国有数の金融会社で、受賞歴のあるプロプライエタリな債券取引プラットフォームの開発を率いている。