マイクロサービスの構築:APIゲートウェイの活用

NGINX | 2015年6月15日

編集者注 – 全7回の記事シリーズが完結しました:

  1. マイクロサービス入門
  2. マイクロサービスの構築:API Gatewayの使用(本記事)
  3. マイクロサービスの構築:マイクロサービスアーキテクチャにおけるプロセス間通信
  4. マイクロサービスアーキテクチャにおけるサービスディスカバリ
  5. マイクロサービス向けイベント駆動型データ管理
  6. マイクロサービスのデプロイ戦略の選択
  7. モノリスからマイクロサービスへのリファクタリング

一連の記事に加え、NGINX Plusを使用したマイクロサービスの実装に関する情報をまとめたeBook「マイクロサービス:設計からデプロイまで」もダウンロードできます。また、新しい「マイクロサービスソリューションのページ」もご覧ください。

マイクロサービスの設計、構築、デプロイについて解説する全7回シリーズの第1回の記事では、マイクロサービスアーキテクチャパターンを紹介しました。マイクロサービスを使用するメリットとデメリットに加え、複雑さはあるものの、通常は複雑なアプリケーションに最適な選択肢となる理由を説明しました。シリーズ第2回となる本記事では、API Gatewayを使用したマイクロサービスの構築について解説します。

アプリケーションを一連のマイクロサービスとして構築する場合、アプリケーションのクライアントがマイクロサービスとどのようにやり取りするかを決める必要があります。モノリシックアプリケーションには、通常は複製され、負荷分散されたエンドポイント群が1つだけあります。一方、マイクロサービスアーキテクチャでは、各マイクロサービスが、通常は細分化されたエンドポイント群を公開します。この記事では、これがクライアントとアプリケーション間の通信に与える影響を検討し、API Gatewayを使用するアプローチを提案します。

はじめに

ショッピングアプリケーション向けのネイティブモバイルクライアントを開発しているとします。任意の商品に関する情報を表示する商品詳細ページを実装する必要があるでしょう。

たとえば、次の図は、AmazonのAndroidモバイルアプリケーションで商品詳細をスクロールしたときに表示される内容を示しています。

携帯電話の画面に表示されたAmazonのAndroid向けモバイルアプリのインデックス化された要素

スマートフォンアプリでありながら、商品詳細ページには多くの情報が表示されます。たとえば、商品名、説明、価格などの基本情報に加えて、次の情報も表示されます。

  • ショッピングカート内の商品数
  • 注文履歴
  • カスタマーレビュー
  • 在庫残少の警告
  • 配送オプション
  • この商品と一緒によく購入される商品、この商品を購入したお客さまが購入したその他の商品、この商品を購入したお客さまが閲覧したその他の商品など、さまざまなおすすめ
  • その他の購入オプション

モノリシックなアプリケーションアーキテクチャを使用する場合、モバイルクライアントはアプリケーションに対して1回のREST呼び出し(GET api.company.com/productdetails/productId)を行い、このデータを取得します。ロードバランサーは、同一構成のN個のアプリケーションインスタンスのいずれかにリクエストをルーティングします。その後、アプリケーションは複数のデータベーステーブルにクエリを実行し、クライアントにレスポンスを返します。

一方、マイクロサービスアーキテクチャでは、商品詳細ページに表示されるデータを複数のマイクロサービスが管理します。以下は、この商品詳細ページの例に表示されるデータを管理するマイクロサービスの一例です。

  • ショッピングカートサービス – ショッピングカート内の商品数
  • Order Service – 注文履歴
  • Catalog Service – 名前、画像、価格などの基本的な製品情報
  • Review Service – カスタマーレビュー
  • Inventory Service – 在庫僅少の警告
  • Shipping Service – 配送業者のAPIから個別に取得した配送オプション、期限、料金
  • レコメンデーションサービス — おすすめの商品

eコマースアプリのモバイルクライアントから7つのマイクロサービスのRESTful APIにアクセスするための仕組みが必要

モバイルクライアントがこれらのサービスにアクセスする方法を決める必要があります。選択肢を見てみましょう。

クライアントとマイクロサービス間の直接通信

理論上、クライアントは各マイクロサービスに直接リクエストを送信できます。各マイクロサービスには、パブリックエンドポイント(https://serviceName.api.company.name)が用意されます。このURLはマイクロサービスのロードバランサーにマッピングされ、利用可能なインスタンスにリクエストが分散されます。製品の詳細情報を取得するために、モバイルクライアントは上記の各サービスにリクエストを送信します。

残念ながら、この方法には課題と制約があります。問題の1つは、クライアントのニーズと、各マイクロサービスが公開するきめ細かなAPIとの間に不一致があることです。この例では、クライアントは7つのリクエストを個別に送信する必要があります。より複雑なアプリケーションでは、さらに多くのリクエストが必要になる可能性があります。たとえばAmazonは、同社の商品ページのレンダリングに数百ものサービスが関与していると説明しています。LAN経由であれば、クライアントがこれほど多くのリクエストを送信することも可能ですが、パブリックインターネット経由では効率が悪すぎる可能性が高く、モバイルネットワーク経由では明らかに現実的ではありません。また、この方法ではクライアントコードがはるかに複雑になります。

クライアントがマイクロサービスを直接呼び出す場合のもう1つの問題は、一部のマイクロサービスがWebに適さないプロトコルを使用している可能性があることです。あるサービスはThriftバイナリRPCを使用し、別のサービスはAMQPメッセージングプロトコルを使用している場合があります。どちらのプロトコルもブラウザーやファイアウォールとの親和性が特に高いわけではなく、内部での使用に適しています。アプリケーションでは、ファイアウォールの外部でHTTPやWebSocketなどのプロトコルを使用する必要があります。

このアプローチには、マイクロサービスのリファクタリングが難しくなるという別の欠点もあります。時間の経過とともに、システムをサービスに分割する方法を変更したくなる場合があります。たとえば、2つのサービスを統合したり、1つのサービスを2つ以上に分割したりすることが考えられます。しかし、クライアントがサービスと直接通信している場合、このようなリファクタリングは非常に困難になる可能性があります。

このような問題があるため、クライアントがマイクロサービスと直接通信することが適切なケースはほとんどありません。

APIゲートウェイの使用

通常は、API Gatewayと呼ばれるものを使用する方がはるかに優れたアプローチです。API Gatewayは、システムへの単一のエントリーポイントとなるサーバーです。オブジェクト指向設計におけるFacadeパターンに似ています。API Gatewayは内部のシステムアーキテクチャをカプセル化し、各クライアントに合わせたAPIを提供します。また、認証、監視、負荷分散、キャッシュ、リクエストの整形と管理、静的レスポンスの処理などを担う場合もあります。

次の図は、一般的なアーキテクチャにおけるAPI Gatewayの位置付けを示しています。

APIゲートウェイにより、eコマースアプリのモバイルクライアントは、7つのマイクロサービスのRESTful APIにアクセスできます

API Gatewayは、リクエストのルーティング、合成、プロトコル変換を担います。クライアントからのすべてのリクエストは、まずAPI Gatewayを経由し、適切なマイクロサービスにルーティングされます。API Gatewayは多くの場合、複数のマイクロサービスを呼び出して結果を集約することで、リクエストを処理します。また、HTTPやWebSocketなどのWebプロトコルと、内部で使用されるWebに適さないプロトコルとの間で変換できます。

API Gatewayは、クライアントごとにカスタムAPIを提供することもできます。通常、モバイルクライアント向けには粗粒度のAPIを公開します。たとえば、商品詳細を取得するシナリオを考えてみましょう。API Gatewayは、モバイルクライアントが1回のリクエストですべての商品詳細を取得できるエンドポイント(/productdetails?productid=xxx)を提供できます。API Gatewayは、商品情報、レコメンデーション、レビューなどの各種サービスを呼び出して結果を統合することで、リクエストを処理します。

API Gatewayの優れた事例として、Netflix API Gatewayが挙げられます。Netflixのストリーミングサービスは、テレビ、セットトップボックス、スマートフォン、ゲーム機、タブレットなど、数百種類ものデバイスで利用できます。当初、Netflixはストリーミングサービス向けに、あらゆるデバイスに対応する汎用型APIを提供しようとしました。しかし、デバイスの種類が多岐にわたり、それぞれ固有のニーズがあるため、うまく機能しないことが分かりました。現在は、デバイス固有のアダプターコードを実行し、各デバイスに合わせたAPIを提供するAPI Gatewayを使用しています。通常、アダプターは平均6~7個のバックエンドサービスを呼び出して各リクエストを処理します。Netflix API Gatewayは、1日に数十億件のリクエストを処理しています。

API Gatewayのメリットとデメリット

ご想像のとおり、API Gatewayの利用にはメリットとデメリットがあります。大きなメリットの1つは、アプリケーションの内部構造をカプセル化できることです。クライアントは個々のサービスを呼び出す必要がなく、ゲートウェイと通信するだけで済みます。API Gatewayは、クライアントの種類ごとに専用のAPIを提供します。これにより、クライアントとアプリケーション間のラウンドトリップ回数が減り、クライアントコードも簡素化されます。

API Gatewayにもいくつかの欠点があります。API Gatewayは、高可用性を確保しながら開発、デプロイ、管理しなければならないコンポーネントがさらに1つ増えることを意味します。また、API Gatewayが開発のボトルネックになるリスクもあります。各マイクロサービスのエンドポイントを公開するには、開発者がAPI Gatewayを更新する必要があります。そのため、API Gatewayの更新プロセスを可能な限り簡素化することが重要です。そうしなければ、開発者はゲートウェイを更新する順番を待たなければなりません。ただし、こうした欠点があるとしても、実際のほとんどのアプリケーションではAPI Gatewayを使用するのが妥当です。

API Gatewayの実装

API Gatewayを使用する動機とトレードオフを確認したところで、次に考慮すべきさまざまな設計上の課題を見ていきます。

パフォーマンスとスケーラビリティ

Netflixほどの規模で事業を展開し、1日に数十億件ものリクエストを処理する必要がある企業は、ごくわずかです。しかし、ほとんどのアプリケーションでは、通常、API Gatewayのパフォーマンスとスケーラビリティが非常に重要です。そのため、非同期のノンブロッキングI/Oをサポートするプラットフォーム上にAPI Gatewayを構築するのが合理的です。スケーラブルなAPI Gatewayの実装には、さまざまなテクノロジーを利用できます。JVMでは、Netty、Vertx、Spring Reactor、JBoss UndertowなどのNIOベースのフレームワークを使用できます。JVM以外の一般的な選択肢としては、ChromeのJavaScriptエンジン上に構築されたプラットフォームであるNode.jsがあります。もう1つの選択肢は、NGINX Plusを使用することです。NGINX Plusは、導入、設定、プログラミングが容易で、成熟したスケーラブルかつ高性能なWebサーバーおよびリバースプロキシを提供します。NGINX Plusでは、認証、アクセス制御、リクエストの負荷分散、レスポンスのキャッシュを管理できるほか、アプリケーションを認識するヘルスチェックと監視も行えます。

リアクティブプログラミングモデルの使用

API Gatewayは、一部のリクエストを適切なバックエンドサービスにルーティングするだけで処理します。それ以外のリクエストについては、複数のバックエンドサービスを呼び出し、その結果を集約して処理します。商品詳細の取得など、一部のリクエストでは、バックエンドサービスへの各リクエストが互いに独立しています。応答時間を最小限に抑えるため、API Gatewayは独立したリクエストを同時に実行する必要があります。ただし、リクエスト間に依存関係がある場合もあります。たとえば、API Gatewayでは、リクエストをバックエンドサービスにルーティングする前に、認証サービスを呼び出してリクエストを検証する必要がある場合があります。同様に、お客さまのウィッシュリストにある商品の情報を取得するには、まずその情報を含むお客さまのプロファイルを取得し、次に各商品の情報を取得する必要があります。APIコンポジションのもう1つの興味深い例は、Netflix Video Gridです。

従来の非同期コールバック方式でAPIコンポジションコードを記述すると、すぐにコールバック地獄に陥ります。コードが複雑に絡み合い、理解しにくく、エラーも発生しやすくなります。はるかに優れた方法は、リアクティブ方式を採用し、API Gatewayコードを宣言的なスタイルで記述することです。リアクティブ抽象化の例としては、ScalaのFuture、Java 8のCompletableFuture、JavaScriptのPromiseがあります。また、Reactive Extensions(RxまたはReactiveXとも呼ばれます)もあります。これは、もともとMicrosoftが.NETプラットフォーム向けに開発したものです。Netflixは、自社のAPI Gatewayで使用するために、JVM向けのRxJavaを開発しました。JavaScript向けにはRxJSもあり、ブラウザーとNode.jsの両方で動作します。リアクティブ方式を採用することで、シンプルかつ効率的なAPI Gatewayコードを記述できます。

サービス呼び出し

マイクロサービスベースのアプリケーションは分散システムであるため、プロセス間通信メカニズムを使用する必要があります。プロセス間通信には2つの方式があります。1つは、メッセージングベースの非同期メカニズムを使用する方式です。実装によっては、JMSやAMQPなどのメッセージブローカーを使用します。Zeromqなど、ブローカーを使用せず、サービス同士が直接通信する実装もあります。もう1つは、HTTPやThriftなどの同期メカニズムを使用する方式です。通常、システムでは非同期方式と同期方式の両方を使用します。さらに、それぞれの方式で複数の実装を使用する場合もあります。そのため、API Gatewayはさまざまな通信メカニズムをサポートする必要があります。

サービスディスカバリ

API Gatewayは、通信する各マイクロサービスの場所(IPアドレスとポート)を把握する必要があります。従来型のアプリケーションであれば、場所をハードコードできる可能性がありますが、最新のクラウドベースのマイクロサービスアプリケーションでは、これは容易ではありません。メッセージブローカーなどのインフラストラクチャサービスは通常、場所が固定されており、OS環境変数で指定できます。しかし、アプリケーションサービスの場所を特定するのは簡単ではありません。アプリケーションサービスの場所は動的に割り当てられます。また、自動スケーリングやアップグレードにより、サービスのインスタンス構成も動的に変化します。そのため、API Gatewayは、システム内の他のサービスクライアントと同様に、システムのサービスディスカバリメカニズムとして、サーバーサイドディスカバリまたはクライアントサイドディスカバリのいずれかを使用する必要があります。後の記事では、サービスディスカバリについてさらに詳しく説明します。ここでは、システムでクライアントサイドディスカバリを使用する場合、API Gatewayがサービスレジストリを照会できる必要がある点に留意してください。サービスレジストリは、すべてのマイクロサービスインスタンスとその場所を格納するデータベースです。

部分的な障害への対処

API Gatewayを実装する際に対処すべきもう1つの課題は、部分障害です。この問題は、あるサービスが、応答が遅い、または利用できない別のサービスを呼び出す場合に、あらゆる分散システムで発生します。API Gatewayがダウンストリームサービスからの応答を待ち続け、無期限に処理をブロックすることは避ける必要があります。ただし、障害への対処方法は、具体的なシナリオと障害が発生したサービスによって異なります。たとえば、商品詳細のシナリオでレコメンデーションサービスが応答しない場合、残りの商品詳細はユーザーにとって引き続き有用であるため、API Gatewayはそれらをクライアントに返す必要があります。レコメンデーションは空にするか、たとえば固定のトップ10リストに置き換えることができます。一方、商品情報サービスが応答しない場合、API Gatewayはクライアントにエラーを返す必要があります。

キャッシュデータが利用可能な場合、API Gatewayはそのデータを返すこともできます。たとえば、製品価格は頻繁には変更されないため、価格サービスが利用できない場合、API Gatewayはキャッシュされた価格データを返すことができます。データはAPI Gateway自体でキャッシュすることも、RedisやMemcachedなどの外部キャッシュに保存することもできます。デフォルトデータまたはキャッシュデータを返すことで、API Gatewayはシステム障害がユーザーエクスペリエンスに影響しないようにします。

Netflix Hystrixは、リモートサービスを呼び出すコードを記述する際に非常に役立つライブラリです。Hystrixは、指定されたしきい値を超えた呼び出しをタイムアウトさせます。また、サーキットブレーカーパターンを実装しており、応答しないサービスをクライアントが無駄に待ち続けることを防ぎます。サービスのエラー率が指定されたしきい値を超えると、Hystrixはサーキットブレーカーを作動させ、指定された期間、すべてのリクエストを即座に失敗させます。Hystrixでは、キャッシュからの読み取りやデフォルト値の返却など、リクエストが失敗した場合のフォールバック処理を定義できます。JVMを使用している場合は、Hystrixの使用をぜひ検討してください。JVM以外の環境で実行している場合は、同等のライブラリを使用してください。

まとめ

ほとんどのマイクロサービスベースのアプリケーションでは、システムへの単一のエントリーポイントとして機能するAPI Gatewayを実装するのが合理的です。API Gatewayは、リクエストのルーティング、合成、プロトコル変換を担います。また、アプリケーションの各クライアントにカスタムAPIを提供します。さらに、キャッシュデータやデフォルトデータを返すことで、バックエンドサービスの障害を隠蔽することもできます。シリーズの次の記事では、サービス間の通信について説明します。

編集部 – 全7回の記事シリーズが完結しました:

  1. マイクロサービス入門
  2. マイクロサービスの構築:API Gatewayの使用(本記事)
  3. マイクロサービスの構築:マイクロサービスアーキテクチャにおけるプロセス間通信
  4. マイクロサービスアーキテクチャにおけるサービスディスカバリ
  5. マイクロサービス向けイベント駆動型データ管理
  6. マイクロサービスのデプロイ戦略の選択
  7. モノリスからマイクロサービスへのリファクタリング

一連の記事に加え、NGINX Plusを使用したマイクロサービスの実装に関する情報をまとめたeBookもダウンロードできます。『マイクロサービス:設計からデプロイまで』

その他のユースケースについて詳しくは、全3回のブログシリーズ「NGINX PlusをAPIゲートウェイとして導入する」をご覧ください。

  • パート1では、複数のユースケースについて詳細な設定手順を説明しています。
  • パート 2では、これらのユースケースを拡張し、本番環境のバックエンドAPIサービスを保護し、セキュリティを確保するために適用できるさまざまな保護対策について説明します。
  • パート3では、NGINX PlusをgRPCサービスのAPIゲートウェイとしてデプロイする方法を説明します。

ゲストブロガーのChris Richardson氏は、初期のAmazon EC2向けJava PaaS(Platform as a Service)である、当初の「CloudFoundry.com」の創設者です。現在は、アプリケーションの開発およびデプロイ方法の改善に向けて、組織にコンサルティングを提供しています。また、マイクロサービスについて「http://microservices.io」で定期的にブログを執筆しています。


共有
タグ: F5 NGINX, 2015, Tech

関連するブログ記事

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
NGINX | 2024/01/18

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する

OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
NGINX | 2023/05/31

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正

Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
NGINX | 2023/02/09

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法

Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINX | 2022/05/24

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング

NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
NGINX | 2018/08/17

SELinuxでNGINXおよびNGINX Plusを使用する

Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。

NGINX PlusによるAWS Auto Scalingグループの負荷分散
NGINX | 2017/03/06

NGINX PlusによるAWS Auto Scalingグループの負荷分散

新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります