マイクロサービス設計パターン

こんにちは、Habr!



近い将来、Sa​​m Newmanの待望の本「 Creating Microservices 」のロシア語翻訳に関する投稿を読んでください。 それまでの間、Arun Guptaによる記事の翻訳を読むことをお勧めします。ArunGuptaの著者は、マイクロサービスアーキテクチャに適用可能な最も興味深いデザインパターンについて説明しています。





マイクロサービスアプリケーションの主な特徴は、記事「マイクロサービス、モノリス、NoOps 」で説明されています。 これらの特性は、機能分解またはサブジェクト指向の設計、明確に定義されたインターフェイス、明示的に公開されたインターフェイス、唯一の責任の原則、および多言語の可能性です。 各サービスは完全に自律的で、完全にスタックされています。 したがって、1つのサービスの実装の変更が他のサービスに影響を与えることはなく、明確に定義されたインターフェイスを介して情報が交換されます。 このようなアプリケーションには多くの利点がありますが、 無料は提供されませんが、NoOpsに関連する深刻な作業が必要です。



しかし、少なくとも部分的にこの作業の規模を想像して、本当にそのようなアプリケーションを作成して何が起こるかを見たいとします。 どうする? そのようなアプリケーションのアーキテクチャはどうなりますか?

マイクロサービスの相互作用を最適化する設計パターンはありますか?







高品質のマイクロサービスアーキテクチャを作成するには、アプリケーションとチームの機能を明確に分離する必要があります。 このようにして、弱いバインディング(RESTインターフェイス)と強い結合(多くのサービスを組み合わせて、より高いレベルのサービスまたはアプリケーションを定義できます)を実現できます。



アプリケーションの一部として「動詞」(チェックアウトなど)または「名詞」(製品)を作成することは、既存のコードを分解する最も効果的な方法の1つです。 たとえば、製品、カタログ、チェックアウトを3つの個別のマイクロサービスとして実装し、相互にやり取りして、注文のバスケットのすべての機能を提供できます。



機能分解は柔軟性、拡張性などを提供しますが、私たちの仕事はアプリケーションを作成することです。 では、個々のマイクロサービスが同一である場合、それらをどのように組み合わせてアプリケーション機能を実装できますか?



これについては、記事で説明します。



アグリゲーターパターン



マイクロサービスを使用する際の最初の、そしておそらく最も一般的な設計パターンは「アグリゲーター」です。



最も単純な形式のアグリゲーターは、多くのサービスを呼び出してアプリケーションで必要な機能を実装する通常のWebページです。 すべてのサービス(サービスA、サービスB、およびサービスC)は軽量RESTメカニズムを使用して提供されるため、Webページは必要に応じてデータを抽出し、処理/表示できます。 たとえば、個々のサービスから受信したデータにビジネスロジックを適用するなど、何らかの処理が必要な場合は、Webページに表示できるようにデータを変換するCDIコンポーネントを使用できます。







アグリゲーターは、何も表示する必要はないが、他のサービスが消費できる高レベルの複合マイクロサービスのみが必要な場合にも使用できます。 この場合、アグリゲーターはすべての個々のマイクロサービスからデータを収集し、それらにビジネスロジックを適用してから、マイクロサービスをRESTエンドポイントとして公開します。 この場合、必要に応じて、それを必要とする他のサービスを使用できます。



このパターンは、DRYの原則に従います。 サービスA、B、およびCにアクセスする必要があるサービスが多数ある場合は、このロジックを複合マイクロサービスに抽象化し、個別のサービスとして集約することをお勧めします。 このレベルで抽象化する利点は、A、B、Cなどの個々のサービスを独立して進化させることができ、複合マイクロサービスがビジネスロジックを実行し続けることです。



注:個々のマイクロサービス(オプション)には、独自のキャッシュレベルとデータベースがあります。 アグリゲーターが複合マイクロサービスである場合、そのようなレベルを持つことができます。



アグリゲーターは、水平および垂直の両方で独立してスケーリングすることもできます。 つまり、Webページの場合、追加のWebサーバーをそれにねじ込むことができ、Java EEを使用する複合マイクロサービスの場合、WildFlyの追加のインスタンスがそれにねじ込まれ、増大するニーズを満たすことができます。



メディエーターパターン(プロキシ)



マイクロサービスを使用する場合の「メディエーター」のパターンは、アグリゲーターの変形です。 この場合、クライアントで集約が発生するはずですが、ビジネス要件に応じて、追加のマイクロサービスが呼び出される場合があります。







アグリゲーターのように、メディエーターは水平および垂直に独立してスケーリングできます。 これは、個々のサービスを消費者に提供するのではなく、インターフェースを介して実行する必要がある状況で必要になる場合があります。



仲介者は正式 (ダム)にすることができます。その場合、リクエストはサービスの1つに単純に委任されます。 また、 インテリジェント (スマート)にすることもできます。この場合、クライアントに送信される前のデータは何らかの変換を受けます。 たとえば、さまざまなデバイスのプレゼンテーションレイヤーをインテリジェントな仲介にカプセル化できます。



チェーンデザインパターン(チェーン)



マイクロサービス設計パターン「チェーン」は、要求に対する単一の統合された応答を提供します。 この場合、サービスAはクライアントからリクエストを受信し、サービスBと通信します。サービスBは、サービスCと通信できます。これらのサービスはすべて、HTTPを介して同期リクエスト/応答メッセージを交換する可能性があります。







要求と応答の通信チェーン全体が完了するまで、つまりクライアントがブロックされることを覚えておくことが最も重要です。 サービス<->サービスBおよびサービスB <->サービスC。サービスBからサービスCへの要求は、サービスAからサービスBとはまったく異なる場合があります。同様に、サービスBからサービスAへの応答は、サービスからの応答と根本的に異なる場合がありますCからサービスB。これは、いくつかのサービスのビジネス価値が組み合わされるすべての場合に最も重要です。



ここで、チェーンを長くしすぎることはできないことを理解することも重要です。 チェーンは本質的に同期的であるため、これは非常に重要です。長くなると、特に応答がWebページを表示する場合、クライアントが待機する時間が長くなります。 この要求と応答のブロックメカニズムを回避する方法があり、それらは次のパターンで説明します。



単一のマイクロサービスで構成されるチェーンは、単一チェーンと呼ばれます。 その後、拡張できます。



デザインパターン「ブランチ」



マイクロサービス設計パターン「Vetka」は「Aggregator」パターンを拡張し、相互に排他的な2つのマイクロサービスチェーンからの応答を同時に処理します。 このパターンは、必要に応じて、異なるチェーンまたは同じチェーンを呼び出すためにも使用できます。







サービスAは、Webページであれ複合マイクロサービスであれ、2つの異なるチェーンで競合できます。この場合、アグリゲーターに似ています。 別のケースでは、サービスAは、クライアントから受信する要求に応じて、1つのチェーンのみを呼び出すことができます。



このようなメカニズムは、JAX-RSエンドポイントルーティングを実装することで構成できます。この場合、構成は動的でなければなりません。



共有データパターン



マイクロサービス設計の原則の1つは自律性です。 つまり、サービスはフルスタックであり、すべてのコンポーネント(ユーザーインターフェイス、ミドルウェア、永続性、トランザクション)を制御します。 この場合、サービスは多言語対応であり、最適なツールですべての問題を解決できます。 たとえば、必要に応じてNoSQLデータウェアハウスを使用できる場合は、この情報をSQLデータベースに入力するよりも、それだけを行う方が適切です。



ただし、特に既存のモノリシックアプリケーションをリファクタリングする場合の典型的な問題は、データベースの正規化に関連しているため、各マイクロサービスは、厳密に定義された量の情報を持っています。 モノリシックアプリケーションがSQLデータベースのみを使用している場合でも、その非正規化によりデータの重複が発生し、場合によっては矛盾が発生します。 移行段階では、一部のアプリケーションでは「共有データ」パターンを適用すると非常に便利です。



このパターンでは、複数のマイクロサービスがチェーンで動作し、キャッシュとデータベースストアを共有できます。 これは、2つのサービス間に強力な接続がある場合にのみお勧めします。 これをアンチパターンと見なす人もいますが、ビジネスの状況によっては、このようなパターンは本当に適切です。 もともとマイクロサービスとして作成されたアプリケーションでは、間違いなくアンチパターンになります。







さらに、マイクロサービスが完全に自律的になるまで克服する必要がある中間段階と考えることができます。



非同期メッセージングパターン



RESTパターンの普及率とわかりやすさにもかかわらず、重要な制限があります。つまり、それは同期的であり、したがってブロックします。 非同期性を提供することは可能ですが、これはアプリケーションごとに異なります。 そのため、一部のマイクロサービスアーキテクチャでは、要求/応答RESTモデルではなくメッセージキューを使用する場合があります。







このパターンでは、サービスAはサービスCを同期的に呼び出すことができ、サービスCは共有メッセージキューを使用してサービスBおよびBと非同期に通信します。 通信サービスA->サービスCは、たとえばWebソケットを使用して非同期にすることができます。 これにより、必要なスケーラビリティが実現します。

REST要求/応答モデルとパブリッシャー/サブスクライバーメッセージングの組み合わせを使用して、目標を達成することもできます。



また、マイクロサービスで使用するのに便利な通信パターンを説明する「マイクロサービスのカップリングと自律 」の記事を読むこともお勧めします。



All Articles