現在のアプリ開発はマイクロサービスを中心に進められています。この手法では、複雑な要素を小さく扱いやすい部品に分解できるため、アプリ開発がこれまでになく容易になりました。サービスディスカバリはマイクロサービスに欠かせない概念であり、本記事で詳しく説明します。
マイクロサービスアーキテクチャは、すべての対象マイクロサービスが調和を保ち、API(RESTやSOAPなど)を通じて絶えず情報をやり取りすることで、初めて成功と呼べます。多くの場合、マイクロサービスは、相互のやり取りや情報交換、機能維持のために、バーチャルまたはコンテナベースの環境が必要となります。
多様なコンテナが利用され、サービスインスタンスが急速に変動するため、マイクロサービス間の円滑な通信には、各インスタンスの正確な所在把握が不可欠です。この作業は面倒に思われがちですが、サービスディスカバリを用いることで解決できます。
これにより、マイクロサービスはエコシステム内の対象インスタンスの存在を迅速に検出できます。基本的には、SDは各インスタンスの所在情報を記録する台帳のような役割を果たします。
インスタンスの所在にネットワーク経路も含まれるため、サービスをリクエストする際にSDメカニズムは重要となります。その必要性について見ていきましょう。
ポートやIPアドレスなどの所在情報に依存して通信を開始するマイクロサービスには、サービスディスカバリが欠かせません。これらの情報が得られなければ、マイクロサービスはサービスの場所を特定できません。
新たなサービスインスタンスが常に変化するため、アプリのサービス所在地を動的に把握するのは難しく、全ての情報を記録することもできません。クラウドベースのアプリの場合も、水平スケーリングが定期的に行われるため、動的かつ手動による所在追跡が可能です。
SDは所在情報を纏め、マイクロサービスへ提供します。これにより、すべてのインスタンスの所在情報がマイクロサービスの利用可能な状態に保たれます。
Kubernetesのサービスディスカバリの動作は、大きく二部構成となっています。まず、インスタンスの登録とその存在の表示を行い、次に登録されたサービスが容易に特定できるように工夫します。
これらの動作に基づき、クライアントサイドディスカバリとサーバーサイドディスカバリという二つの主要なSDパターンが存在します。どちらもメリットとデメリットがあり、それぞれ異なる方式で機能します。次に、その内容を説明します。
サービスクライアントは、サービスプロバイダを見つけるために適合するサービスレジストリ(SR)を探索します。また、ロードバランシングアルゴリズムを用いて適切なオープンソースのサービスインスタンスを選定し、リクエストを送信します。
サービスが起動すると、インスタンスの所在情報はSRに即時記録されます。サービスインスタンスが停止すれば、その情報は削除される仕組みとなっており、このプロセスはハートビート方式に基づいて継続されます。
ロードバランシングが導入される際、この方式は利用可能なサービスインスタンスの情報をクライアントに提供し、最適な判断を下すのに役立ちます。結果として、クライアントは余力のあるインスタンスを意識でき、負荷分散が容易となります。
初回のクエリは、中央サーバ―であるディスカバリサーバへ送信されます。ディスカバリサーバは、既存インスタンスの台帳のように機能し、その情報を抽象化します。
多くの場合、サービスは適合するAPIゲートウェイの背後に配置され、APIセキュリティが確保されます。これらが利用できない場合、クライアント側で負荷分散や認証などの補完処理が必要となります。
Netflix OSSはこの方式の実例です。この場合、Netflix EurekaがSRとして利用され、サービスインスタンスの統合管理を行うREST APIを提供します。また、問い合わせ可能なインスタンスの管理も行い、ロードバランシングにはNetflix RibbonがIPCクライアントとして使用されます。
クライアントサイドSDの意味が明確になったので、そのメリットにも注目しましょう。
まず、回転するSRエンティティが関与しないため、非常にシンプルで使いやすい方式です。
メリットは大きい一方で、いくつかの欠点も存在します。以下にそのデメリットを挙げます。
この方式では、クライアントがサービスレジストリの存在を意識するよう求められます。むしろ、クライアントのリクエストは専用のルーターが処理し、代わりにSRを検索して既存のインスタンスを検出し、転送します。
負荷分散や最適なサービスインスタンスの検出は心配する必要がなく、APIゲートウェイが受信リクエストを処理可能な最適エンドポイントを選びます。
ここで重要なのは、クライアントサーバからのリクエストを受け取り、目的地へ転送するサーバーサイドのサーバです。正確な動作のため、適切なクライアントの所在を探し出すサービス所在レジストリが維持され、クライアントによる手動の介入は不要となります。
ロードバランシングが採用されていなくても、クライアントのリクエストはロードバランサーのように処理されます。ここでも、サービスが開始されるとインスタンスは自動的に登録され、サービス終了と共に即座に登録解除されます。
Amazon Web ServicesのElastic Load Balancerは、このサービスディスカバリ方式の実例です。ELBは、サービスが受ける外部および内部のトラフィックの分散を担います。
ELBは、DNSを用いてTCPまたはHTTPベースのリクエストをクライアントから受け付けます。リクエストが成功すると、ELBはEC2コンテナやEC2インスタンスへのトラフィック分散を開始します。これらのリソースは直接ELBに登録され、追加のSRは不要です。
MarathonやKubernetesなどの特定環境では、各クラスターにサーバーサイドロードバランサーとして機能するプロキシが配置され、サービスのポートやIPアドレスを用いてすべての受信リクエストをルーティングします。
その後、リクエストはクラスター内の稼働中のインスタンスに転送されます。この方式の採用理由は、以下のいくつかの利点にあります。
この方式の欠点は、以下の通りです。
サービスディスカバリの意味を理解するには、主要な要素であるサービスレジストリについて知ることが推奨されます。これは、すべてのネットワーク所在情報を管理するデータベースです。
SDメカニズムはネットワーク所在情報を収集し、SRに保存します。マイクロサービスを正しく導くためには、サービスレジストリが常に更新され、容易にアクセスできる状態であることが重要です。
クライアントはSRを利用してネットワーク経路を把握し、通信を開始します。さらに、レプリケーションプロトコルを使用するサーバークラスターもSRの一部となります。
前述の通り、サービスディスカバリを実施するマイクロサービスは、インスタンスの所在情報を保存するSRが必要です。円滑なSDのためには、効果的な登録と活用が求められます。以下に二つの選択肢を示します。
この方式では、登録および登録解除の全ての責任を、サービスインスタンス自体が担います。必要に応じて、ハートビートリクエストを送ることで登録を維持することもあります。
シンプルで独立性が高いため、このモデルが好まれます。他のシステムエンティティを必要とせずに進行できますが、サービスインスタンスがサービスレジストリに統合されるため、各フレームワークや言語ごとの登録コードの実装が求められ、複雑になる面もあります。
別の方法を検討する場合、サードパーティ登録が選択肢となります。この方式では、サービスインスタンスは登録の責任を負わず、実行中のサービスインスタンスの記録を保持するサービスレジスターなどの追加コンポーネントが担当します。
この仕組みを実現するには、展開環境のポーリングとイベント購読が必要です。新たなサービスインスタンスが検出されると所在情報が自動的に記録され、終了したインスタンスは即座に登録解除されます。
サービスレジストリと直接連携しないため、利用するフレームワークや言語ごとに特有のロジックを実装する必要がありません。
このプロセスの展開方法は、使用する戦略の効果、適切なリソースへのアクセス、そして正しい実装手法によって決まります。前述のセクションでは、いくつかの戦略と基本要件について説明しました。次に、実際に採用可能な手法について紹介します。
従来のDNSライブラリをクライアントとして利用するDNSベースの方式でSDを実装できます。この実装では、各マイクロサービスがDNSゾーンファイルにアクセスし、広範なDNSルックアップを実施して他のマイクロサービスを特定します。それが困難な場合、NGINXを用いてマイクロサービスを設定します。
その後、これらのマイクロサービスはDNSをポーリングし、SDメカニズムが実現されます。使いやすく、主要なプログラミング言語で機能し、ほとんどコードの変更が不要です。
しかし、DNSの使用には限界があります。たとえば、複数のクライアントに対して異なるキャッシングセマンティクスを用いると、DNSは十分なパフォーマンスを発揮せず、TTLの調整が必要となります。また、ゾーンファイルの管理や追加が求められる場合、この方式はややコストがかかります。
DNS単体では不十分なため、堅牢性を高めるために追加のリソースが必要となり、運用コストも増加します。
この実装方式では、主にConsulやZookeeperが重要な役割を果たします。通信にはサイドカーが用いられ、マイクロサービスはローカルホスト上のプロキシと連携するよう設計されます。
さらに、SDと情報をやり取りし、プロキシの構成において重要な役割を担う追加プロセスが利用されます。実例として、Zookeeperを用いてSmartStackが構築され、Consulを利用する場合は、幅広いインターフェースでサイドカー処理が可能となります。StripeがHAProxyを使用してConsulのデータを複製しているのもその一例です。
この方式は、コードの透明性など多くの利点があるため好まれています。開発者は、マイクロサービス間の相互作用を気にせず、好きなプログラミング言語を使用できます。しかし、その透明性にはいくつかの妥協が伴い、例えばサイドカーはSDホストへのアクセスが制限され、利用されるプロキシは細やかな取引に対応できない場合があります。
また、サイドカーの利用はプロセス全体の遅延を引き起こし、各マイクロサービスに余分な処理を強いることになります。さらに、新たなマイクロサービスごとにサイドカーの再調整とインストールが必要となり、作業量が増大します。
この方式では、開発者に直接APIが提供され、Ribbonのようなライブラリを使用して、特定のサービスディスカバリソリューションと即時通信を確立します。
ここでは、開発者が直接管理を行い、その結果、いくつかの妥協が求められることもあります。API呼び出しを明示的に行うために、マイクロサービスのコードに精通している必要があります。しかし、この方式の利点は、リソース固有ではなく、様々なホストに対応できる点です。
展開プロセスは非常にシンプルで、各サービスごとにクライアントライブラリを展開する必要はありません。ただし、この方式は、ポリグロット環境で幅広い言語に対応するクライアントライブラリに依存する必要があります。
マイクロサービスへの移行において、サービスディスカバリの概念を理解することは非常に重要です。SDは、マイクロサービス同士の連携を可能にし、適切なネットワーク経路情報を提供して正しい方向へ導きます。
本ガイドでは、以下について説明しました:
マイクロサービスの利用を検討する際は、自動かつ即時のSDメカニズムを十分に理解することが、サービスインスタンスの検出を容易にし、円滑なマイクロサービス運用に寄与します。
最新情報を購読