MicroservicesVsSOA / The World of Service-Based Architectures


サービスベースアーキテクチャの世界

要約

本論に入る前の背景説明。

導入

microservicesもSOAもサービスベースのアーキテクチャであり、サービスを使ってさまざまな機能を実装していくものだ。スタイルは違っても両者の共通点は多い。

共通点のひとつは、分散型であること。RESTやSOAP、AMQP、JSM、MSMQ、RMI、.NET Remotingなどのさまざまなリモートアクセスプロトコルを利用する。 モノリシックなアーキテクチャに対する利点は、スケーラビリティや疎結合性などがある。 また、コンポーネントは自己完結型になり、変更やメンテナンスがしやすいモジュール化されたものになる。

サービスベースのアーキテクチャにおけるモジュラリティとは、アプリケーションの各部分を自己完結型のサービスにカプセル化して、他のコンポーネントやサービスに依存することなく個別に設計・開発・テスト・デプロイできるようにすることを指す。いわゆるビッグバンアプローチではなく、小さい単位でのリファクタリングやリプレイスができるようになる。

残念ながら、分散アーキテクチャも万能ではない。複雑になるしコストも高くつく。この章では、サービスベースのアーキテクチャにまつわる諸問題についてとりあげる。

サービス契約

サービス契約とは、リモートサービスとそのコンシューマー(クライアント)との間でやりとりするデータやその書式に関する取り決めのこと。 軽い気持ちで作ってしまってはいけなくて、いろいろ注意すべきことがある。

大きく分けると、サービスベースの契約とコンシューマー主導の契約の二種類がある。その違いは、どの程度のコラボレーションが発生するかということ。 サービスベースの契約では、サービスだけが契約のオーナーになる。コンシューマーの意向を気にせずに契約を変更できる。 コンシューマーは、サービス契約の変更を追いかける必要がある。

いっぽうコンシューマー主導の契約では、サービスとコンシューマーとの間のコラボレーションがあって、コンシューマーのニーズを考慮した契約になる。 一般に、このタイプの契約では、どんなコンシューマーがどのようにサービスを使うのかを、サービス側が把握しておかなければいけない。

もうひとつ重要なトピックがある。それは、サービス契約のバージョン管理。サービス契約を変更したときのコンシューマーへの影響や下位互換性などがからんでくる。

バージョン管理をすれば、契約の変更を伴う新しい機能追加をしながら下位互換性も維持できる。 この章で伝えたい重要なことのひとつは、たとえ「バージョン管理とかいらないよね」と思っていたとしても黙ってバージョン管理しておけということ。その方法は大きく分けてふたつ。ホモジーニアス(同種)なバージョン管理とヘテロジーニアス(異種)なバージョン管理。

ホモジーニアスなバージョン管理は、同じサービス契約に対して複数のバージョン番号を使う。図1-1で、コンシューマーAとコンシューマーBはどちらも同じ円形の契約を使っているがバージョン番号が異なる。 たとえば、何かの発注データを表すXMLベースの契約だったとする。バージョン1.1では、受取人が不在の際の指示を表すフィールドが追加されたなど。こんな場合に元の契約をバージョン1.0として残しておけば、新しいフィールドをoptionalとして扱える。

mvso_0101.png

図1-1:契約のバージョン番号

ヘテロジーニアスなバージョン管理は、複数のタイプの契約を扱う。 コンシューマー主導の契約の考え方に近いものだ。 新しい機能が追加されたときには、その機能をサポートする新しい契約を用意する。 図1-1と図1-2を見比べてみると、図1-2では契約の種類(図の形)が違っていることがわかる。 この形式は、JMSベースのメッセージングシステムでよく使われている。

mvso_0102.png

図1-2:複数の契約

バージョン管理の目的は、下位互換性を提供すること。これを心がけていれば、新機能をデプロイしたりするときに他のコンシューマーとの既存の契約を気にせずにすむようになる。

最後にもうひとつ。契約を変更する際には、いつ変更されるのかや特定のバージョンがいつまでサポートされるのかなどについて、コンシューマーにきちんと知らせることを心がけること。コンシューマーの数が多すぎるためにそれが難しいこともあるが、そんな場合に使える方法を第4章で説明する。


すみません。時間切れのため、ここから先はGoogle翻訳の結果をそのままはりつけただけです……。


サービスの可用性

サービスの可用性とサービスの応答性は、すべてのサービスベースのアーキテクチャに共通する2つの他の考慮事項です。これらのトピックの両方は、サービスコンシューマがリモートサービスと通信する能力に関連していますが、わずかに異なる意味を持ち、さまざまな方法でサービスコンシューマが対応します。

サービス可用性とは、リモートサービスがタイムリーに要求を受け入れる能力(例えば、リモートサービスへの接続を確立する能力)を指す。サービス応答性とは、サービス消費者がサービスから適時の応答を受け取る能力を指す。図1-3の図は、この違いを示しています。

mvso_0103.png

図1-3:サービスの可用性と応答性

これらのエラー条件の最終結果は同じですが(サービス要求を処理することはできません)、さまざまな方法で処理されます。サービスの可用性はサービスの接続性に関係するため、設定した回数だけ接続を再試行するか、可能であれば後で処理するために要求をキューに入れることを除いて、サービスコンシューマーが行うことはほとんどありません。

サービスの応答性は、はるかに扱いにくいです。サービスにリクエストを正常に送信したら、応答を待つ時間はどれくらいですか?サービスの速度が遅いのですか、または応答が送信されないようにサービスで何かが起きましたか?

タイムアウト条件の解決は、リモートサービス接続のより困難な側面の1つになります。合理的なタイムアウト値を決定する一般的な方法は、最初に負荷の下でベンチマークを確立して最大応答時間を取得し、可変負荷条件を考慮する余分な時間を追加することです。たとえば、ベンチマークを実行し、特定のサービス要求の最大応答時間が2,000ミリ秒であるとします。この場合、高負荷状態を考慮してその値を2倍にすると、4,000ミリ秒のタイムアウト値になります。

これはサービス応答のタイムアウトを計算するための合理的な解決策のように思えるかもしれませんが、問題が詰まっています。まず、サービスが実際に停止していて実行されていない場合、すべての要求はサービスが応答していないと判断する前に4秒待たなければなりません。これは、サービス要求のエンドユーザにとっては非効率的で迷惑である。もう1つの問題は、ベンチマークが正確でない可能性があり、重い負荷の下でサービス応答が実際に計算した4秒ではなく、5秒の平均であることです。この場合、サービスは実際に応答していますが、サービス消費者はタイムアウト値が低すぎるため、すべての要求を拒否します。

この問題に対処する一般的な手法は、回路ブレーカパターンを使用することです。サービスが適時に応答しない(またはまったく応答しない)場合、サービス消費者はタイムアウト値の発生を待つ時間を無駄にする必要がないように、ソフトウェア回路ブレーカがスローされます。クールなことは、物理的な回路遮断器とは異なり、サービスが応答し始めるか利用可能になると、このパターンを実装してリセットすることができるということです。 Ribbon from Netflixを含む多くのオープンソースの回路ブレーカパターンの実装があります。マイケル・ナイガードの「Release it!」の回路ブレーカ・パターンの詳細を読むことができます。 (Pragmatic Bookshelf)。

タイムアウト値を扱うときは、すべての要求に対してグローバルタイムアウト値を使用しないようにしてください。代わりに、コンテキストベースのタイムアウト値の使用を検討し、常にアプリケーションを再構築または再デプロイすることなく、さまざまな負荷条件に迅速に対応できるように、これらを外部で構成可能にしてください。別のオプションは、コードに埋め込まれた「スマートタイムアウト値」を作成して、変化する負荷条件に基づいて調整することができます。たとえば、負荷の高いアプリケーションやネットワークの問題に対応して、タイムアウト値を自動的に増やすことができます。負荷が減少し、応答時間が速くなると、アプリケーションは特定の要求の平均応答時間を計算し、それに応じてタイムアウト値を下げることができます。


セキュリティ

サービスは一般にサービスベースのアーキテクチャではリモートからアクセスされるため、サービスコンシューマが特定のサービスにアクセスすることを許可することが重要です。状況に応じて、サービスコンシューマは認証され、認可される必要があります。認証とは、通常、ユーザー名とパスワードを使用してサインオン資格情報を使用して、サービスコンシューマがサービスに接続できるかどうかを示します。場合によっては、認証では不十分です。サービスコンシューマがサービスに接続できるということは、必ずしもそのサービス内のすべての機能にアクセスできるわけではありません。認可とは、サービスコンシューマがサービス内の特定のビジネス機能にアクセスできるかどうかを示します。

初期のSOA実装では、セキュリティは大きな問題でした。安全性の高いサイロベースのアプリケーションに配置されていた機能は、企業全体にとって突然グローバルに利用されていました。この問題は、サービスについての考え方や、サービスにアクセスできない消費者からサービスを保護する方法に大きな変化をもたらしました。

マイクロサービスでは、セキュリティは、ミドルウェアコンポーネントがセキュリティベースの機能を処理しないため、主に挑戦になります。 代わりに、各サービスは単独でセキュリティを処理する必要があります。場合によっては、アプリケーションのセキュリティ面を処理するためにAPIレイヤをよりインテリジェントにすることもできます。 私がうまく機能しているマイクロサービスで実装されているセキュリティ設計の1つは、認証を別のサービスに委任し、認証自体の責任をサービス自体に置くことです。 この設計は、認証と認可の両方を別々のセキュリティサービスに委譲するように変更することもできますが、リモートセキュリティサービスの不正を避け、より少ない外部依存関係で強力な境界付きコンテキストを作成するために、

トランザクション

トランザクション管理は、サービスベースのアーキテクチャでは大きな課題です。ほとんどの場合、トランザクションについては、ほとんどのビジネスアプリケーションで使用されるACID(アトミック性、一貫性、分離性、耐久性)トランザクションを参照しています。 ACIDトランザクションは、単一の要求内で複数のデータベース更新を調整することによってデータベースの一貫性を維持するために使用されるため、処理中にエラーが発生した場合、その要求に対してすべてのデータベースの更新がロールバックされます。

サービスベースのアーキテクチャーが一般的に分散アーキテクチャーであることを考えると、複数のリモート・サービス間でトランザクション状況を伝播して維持することは非常に困難です。図1-4に示すように、1つのサービス要求(赤いXの横のボックスで表される)は、要求を完了するために複数のリモートサービスを呼び出す必要があります。ダイアグラムの赤いXは、このシナリオでACIDトランザクションを使用することが可能でないことを示しています。

mvso_0104.png

図1-4:サービストランザクション管理

マイクロソフトのアーキテクチャとは異なり、通常は単一のビジネス要求を実行するために複数のサービスが使用されるため、トランザクションの問題はSOAではるかに一般的です。これについては、第3章の「サービスオーケストレーション」のセクションで詳しく説明します。

ACIDトランザクションを使用するのではなく、サービスベースのアーキテクチャはBASEトランザクションに依存しています。 BASEは、基本的な可用性、ソフト状態、最終的な一貫性を含むスタイルのファミリです。 BASEトランザクションに依存する分散アプリケーションは、すべてのトランザクションの一貫性ではなく、最終的な一貫性をデータベースに求めています。 BASEトランザクションの古典的な例は、ATMに入金しています。 ATMを使用して現金を口座に入金すると、入金がアカウントに表示されるまで数分から数時間かかることがあります。言い換えれば、お金があなたの手を去ったが、あなたの銀行口座に達していない、柔らかい移行状態があります。私たちはこのタイムラグに寛容で、柔らかい状態と最終的な一貫性に頼って、すぐにお金がアカウントに届くことを知り、信頼しています。バッチ・ジョブは、全体的なシステム・ビューから見たときに最終的な一貫性に依存することもあります。

サービスベースのアーキテクチャの世界に切り替えるには、トランザクションと一貫性についての考え方を変える必要があります。最終的な一貫性とソフトな状態に頼ることができず、トランザクションの一貫性が要求されない状況では、ビジネスロジックを単一のサービスにカプセル化するためにサービスをより粗くすることができ、ACIDトランザクションを使用してトランザクションレベル。また、リクエストの状態が一貫している場合にイベント駆動の手法を利用して通知をコンシューマにプッシュすることもできます。このテクニックは、アプリケーションに相当な量の複雑さを追加しますが、BASEトランザクションが使用されるときのトランザクション状態の管理に役立ちます。

複雑すぎますか?

サービスベースのアーキテクチャは、モノリシックアプリケーションよりも大幅に改善されていますが、わかるように、多くの考慮事項があります。サービス契約、可用性、セキュリティ、およびトランザクション(いくつか例を挙げると)など、残念ながら、マイクロサービスやSOAなどのサービス・ベースのアーキテクチャ・アプローチへの移行には、トレードオフが伴います。このため、分散コンピューティングが直面している多くの問題に対処する用意ができていなければ、サービスベースのアーキテクチャソリューションに乗り出すべきではありません。

この章で特定されている問題は複雑ですが、確かにそれほど目立つものではありません。サービスベースのアーキテクチャを使用するほとんどのチームは、オープンソースツール、商用ツール、およびカスタムソリューションの組み合わせにより、これらの課題にうまく対応し解決することができます。

サービスベースのアーキテクチャは複雑ですか?絶対に。ただし、複雑さが増すと、開発チームの生産性が向上し、より信頼性と堅牢性の高いアプリケーションを作成し、全体的なコストを削減し、市場投入までの時間を短縮することができます。次の3つの章では、マイクロサービスとSOAを比較して、どのアーキテクチャパターンが適切かを判断するのに役立ちます。

担当者のつぶやき

みんなの突っ込み