こんにちは。Infrastructure チームの笠井(@unblee)です。
最近私が取り組んでいた「Wantedly への API Gateway(Ambassador)の導入」についてブログを書きます。このブログでは、API Gateway Pattern の説明から、実際に導入した背景や取り組み、将来への展望について紹介したいと思います。
TL;DR
- API Gateway Pattern とは、クライアント・マイクロサービス間のネットワークラウンドトリップの低減およびマイクロサービス間のエントリポイントの集約を主な目的としたアーキテクチャのベストプラクティスのこと
- Wantedly の近い将来における開発・アーキテクチャを見据えた技術的先行投資として API Gateway の導入を決めた
- 最初のステップとして、www.wantedly.com ドメイン以下の Path Routing の実現を目的として API Gateway を実際に本番環境に導入した
- 描いた未来像へ向けてより広いスコープでの API Gateway の活用方法をプロダクトチームと連携して提案・実現しつつ Wantedly というプロダクトの成長に貢献していく
API Gateway Pattern とは何なのか?
まず、そもそも API Gateway Pattern とは何かという部分に対して説明したいと思います。すでに Web上には API Gateway Pattern についてまとめた記事やドキュメントが多くありますが、個人的には Web 上で閲覧可能かつ日本語で読めるものでは、Microsoft が公開しているドキュメント API ゲートウェイ パターンと、クライアントからマイクロサービスへの直接通信との比較 が一番よくまとまっていてわかりやすいのでこれを参照しながら簡単にまとめます。
まず API Gateway Pattern という概念について。これは、前提としてサービスのアーキテクチャとしてマイクロサービスアーキテクチャを採用しているサービス(Wantedly 含む)が対象です。
資料では、マイクロサービスアーキテクチャを採用しているかつクライアントとマイクロサービスが直接通信を行う(ロードバランサーは除く)サービスにおいては、以下の問題があると指摘されています。
・結合: API ゲートウェイ パターンがないと、クライアント アプリは内部マイクロサービスと結合されます。 クライアント アプリでは、アプリケーションのさまざまな領域がマイクロサービスにどのように分解されたかを把握する必要があります。 内部マイクロサービスを進化させてリファクタリングするときに、そのようなアクションは、クライアント アプリから内部マイクロサービスへの直接参照が原因でクライアント アプリに対する破壊的変更を生じさせるため、メンテナンスに影響が及びます。 クライアント アプリには頻繁な更新が必要なので、ソリューションの進化が困難になります。
・膨大な数のラウンドトリップ: クライアント アプリの 1 つのページ/画面のために、複数のサービスを何回も呼び出す必要がある場合があります。 その結果、クライアントとサーバー間のネットワーク ラウンド トリップが多くなり、待機時間が大幅に長くなることがあります。 中間レベルで処理される集約によって、クライアント アプリのパフォーマンスとユーザー エクスペリエンスを向上できる可能性があります。
・セキュリティ上の問題: ゲートウェイがない場合、すべてのマイクロサービスが "外の世界" に対して公開されることになり、クライアント アプリで直接使用されない内部マイクロサービスを非表示にした場合よりも攻撃サーフェスが大きくなります。 攻撃サーフェスが小さいほど、アプリケーションの安全性は高くなります。
・横断的な問題: パブリックに公開される各マイクロサービスは、認可や SSL などの問題を処理する必要があります。 多くの場合、これらの問題を 1 つの層で処理することができるため、内部マイクロサービスが単純化されます。
https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/architect-microservice-container-applications/direct-client-to-microservice-communication-versus-the-api-gateway-pattern#why-consider-api-gateways-instead-of-direct-client-to-microservice-communication より引用
以上の問題点を解決するために、特定かつ複数のマイクロサービスへのルーティング機能を持ったコンポーネントをクライアントとマイクロサービス間に配置し、クライアントからのリクエストを集約するようなアーキテクチャを API Gateway Pattern と呼びます。
https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/architect-microservice-container-applications/media/direct-client-to-microservice-communication-versus-the-api-gateway-pattern/custom-service-api-gateway.png より引用
資料では API Gateway Pattern の主な機能・利点は以下のようなものであると言及しています。欠点については API ゲートウェイ パターンの欠点 を参照してください。
リバース プロキシ/ゲートウェイ ルーティング。 API ゲートウェイは、マイクロサービスのエンドポイントに要求をリダイレクト/ルーティングする (レイヤー 7 ルーティング、通常は HTTP 要求) ためのリバース プロキシを提供します。 ゲートウェイはクライアント アプリ用に 1 つのエンドポイントまたは URL を提供し、要求を内部マイクロサービスのグループに内部的にマッピングします。 このルーティング機能は、クライアント アプリをマイクロサービスから分離するのに役立つだけでなく、モノリシック API とクライアント アプリの間に API ゲートウェイを設置してモノリシック API を刷新するときにも便利です。将来多数のマイクロサービスに分割されるまでの間従来のモノリシック API を使い続けながら、新しい API を新しいマイクロサービスとして追加できます。 API ゲートウェイがあるため、クライアント アプリは、使用されている API が内部マイクロサービスとして実装されているのか、モノリシック API として実装されているのかを関知しません。さらに重要なことに、モノリシック API をマイクロサービスに進化させてリファクタリングするときに、API ゲートウェイのルーティングのおかげでクライアント アプリが URI 変更の影響を受けずに済みます。
要求の集約。 ゲートウェイ パターンの一部として、複数の内部マイクロサービスに対する複数のクライアント要求 (通常は HTTP 要求) を 1 つのクライアント要求に集約することができます。 このパターンは特に、クライアントのページ/画面が複数のマイクロサービスからの情報を必要とする場合に便利です。 この方法では、クライアント アプリが API ゲートウェイに 1 つの要求を送信します。API ゲートウェイは内部マイクロサービスに複数の要求をディスパッチし、結果を集約し、すべてをクライアント アプリに送り返します。 この設計パターンの主な利点と目的は、クライアント アプリとバックエンド API 間の頻繁な通信を削減することです。これは、マイクロサービスが置かれているデータセンターの外にあるリモート アプリ (モバイル アプリや、クライアントのリモート ブラウザー内の JavaScript から送信された SPA アプリからの要求など) において特に重要です。 サーバー環境で要求を実行する通常の Web アプリ (ASP.NET Core MVC Web アプリ) の場合は、リモート クライアント アプリよりも待機時間がはるかに短いため、このパターンはそれほど重要ではありません。
横断的な問題またはゲートウェイのオフロード。 各 API ゲートウェイ製品で提供される機能に応じて、個々のマイクロサービスからゲートウェイに機能をオフロードできます。これにより、横断的な問題を 1 つの層にまとめて、各マイクロサービスの実装を単純化することができます。 これは特に、次の機能のような、内部マイクロサービスごとに正しく実装することが難しい専門的な機能に役立ちます。
・認証と承認
・サービス探索の統合
・応答キャッシュ
・再試行ポリシー、サーキット ブレーカー、QoS
・レートの制限と調整
・負荷分散
・ログ記録、トレース、相関関係
・ヘッダー、クエリ文字列、クレーム変換
・IP ホワイトリスト登録
https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/architect-microservice-container-applications/direct-client-to-microservice-communication-versus-the-api-gateway-pattern#main-features-in-the-api-gateway-pattern より引用
つまり API Gateway とはクライアント・マイクロサービス間のネットワークラウンドトリップの低減およびマイクロサービス間のエントリポイントの集約を主な目的としたアーキテクチャのベストプラクティスの一つと言えます。
なお、より特定のアプリケーションを意識して用途を限定・特化させる場合 Backends For Frontends(BFF)とも呼ばれます。
Wantedly における API Gateway の導入目的
現時点の Wantedly においては、厳密に言えば「API Gateway を導入しなければ解決出来ない技術的な問題」は存在しません。そのため問題解決という文脈においては API Gateway は不要とすら言えます。
では何故今導入するのか?についてですが、一番の目的は「Wantedly の近い将来における開発・アーキテクチャを見据えた技術的先行投資」です。今後開発者やマイクロサービスの増加にしたがって開発をスケールさせるときに、必要な抽象化やインタフェースを統一する流れを必要になってから急いで作るのではなく、作る余地を今のうちに作っておきたいという考えから導入の検討を始めました。
このとき考えていた未来像は以下のようなものです。
- マイクロサービスの抽象化
- 内部実装(マイクロサービス)の隠蔽
- 同じ Path でもヘッダや重み付け等によってルーティングの Upstream を動的に制御できるようにする
- マイクロサービスの切り出し支援
- 式年遷宮(段階的 Deprecation)支援
- Canary Release
- インタフェースの統一
- 今後開発者が増えていく中で、外に向けた適切なインタフェースの合意が取りづらくなっていくことが考えられるため、外に出すには必ず特定のインタフェースを満たさなくてはいけないという強制力を持たせたい
- 外部に露出させるには必ず API Gateway を通すようにルール化する等外部と内部を明確に分離できれば、内部は安全なものとして認証を省略できるようになる
現状
現在 Wantedly では、API Gateway として Ambassador を www.wantedly.com へ導入しています。
新機能のリリースにともなって、www.wantedly.com ドメイン以下の特定の Path へのリクエストを指定した別のマイクロサービスにルーティングする必要があるという要望が別に上がってきたため、これを取り込む形で一旦は「www.wantedly.com 以下の Path Routing の実現を目的」として API Gateway を実際に本番環境に導入することに決めました。
AWS EC2 上の Kubernetes クラスタで Wantedly のサービスは運用されているため、Path Routing だけを目的にするなら AWS の Application Load Balancer(ALB)や他の手段でも実現出来ます。しかしながら、ALB では将来的に API Gateway に期待する役割を満たすことが出来ないと判断したため、API Gateway の導入を進めました。
またもう一つの理由として、同時期に進められていた「Istio を用いた新しい開発手法の構築」に API Gateway 的な立ち位置のコンポーネントが必要だったという理由もあります。こちらについては詳細は Istioを使って「Fast, Dependency-Agnostic, Isolated」な開発体験を実現した話 という Story で解説されているためそちらを参照してください。また、CloudNative Days Tokyo 2020 09/08 19:00-19:40 Track F において DX チームの大坪とインターンの森本が発表するのでそちらもぜひご聴講ください。
検討の結果、API Gateway として Ambassador を導入することに決まり、検証環境での動作確認をした上で Path Routing 機能だけを有効化したミニマルな状態で本番環境へ導入しました。
今後の展望
今回、Wantedly の Infrastructure チームでは API Gateway の検討、本番環境への導入までを行いました。現状はまだ Path Routing でしか活用出来ていませんが、当初考えていた「将来的な開発者やマイクロサービスの増加にしたがって開発をスケールさせるときに必要なアクションが出来る状態」にはなったと思います。
もともと、未来像として検討していたのは、以下を API Gateway で実現できるようになることでした。
- マイクロサービスの抽象化
- 内部実装(マイクロサービス)の隠蔽
- 同じ Path でもヘッダや重み付け等によってルーティングの Upstream を動的に制御できるようにする
- マイクロサービスの切り出し支援
- 式年遷宮(段階的 Deprecation)支援
- Canary Release
- インタフェースの統一
- 今後開発者が増えていく中で外に向けた適切なインタフェースの合意が取りづらくなっていくことが考えられるため外に出すには必ず特定のインタフェースを満たさなくてはいけないという強制力を持たせたい
- 外部に露出させるには必ず API Gateway を通すようにルール化する等外部と内部を明確に分離できれば内部は安全なものとして認証を省略できるようになる
今後は上記のような未来像へ向けて、より広いスコープでの API Gateway の活用方法をプロダクトチームと連携して提案・実現しつつ、Wantedly というプロダクトの成長に貢献していきたいと思います。
参考資料
- Blog/Document
- API ゲートウェイ パターンと、クライアントからマイクロサービスへの直接通信との比較 | Microsoft Docs
- API ゲートウェイ - Azure Architecture Center | Microsoft Docs
- ゲートウェイ ルーティング パターン - Cloud Design Patterns | Microsoft Docs
- ゲートウェイ集約パターン - Cloud Design Patterns | Microsoft Docs
- ゲートウェイ オフロード パターン - Cloud Design Patterns | Microsoft Docs
- API gateway pattern
- Optimizing the Netflix API - Netflix TechBlog
- Embracing the Differences : Inside the Netflix API Redesign
- Building Microservices Using an API Gateway | NGINX
- The Role of API Gateways in Microservice Architectures - The New Stack
- メルカリのマイクロサービス移行の進捗 (2019年冬) - Mercari Engineering Blog
- マイクロサービス・アプリケーションにストラングラー・アプリケーション・パターンを適用する
- Ambassador Edge Stack vs. Other Software | Ambassador
- My experiences with API gateways… - Mahesh Mahadevan - Medium
- モダンBFFを活用した既存APIサーバーの再構築 - クックパッド開発者ブログ
- Traffic Shifting/Splitting — envoy 1.14.0-dev-1d751a documentation
- https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#envoy-api-msg-route-routeaction-requestmirrorpolicy
- Slide
Photo Credit
Photo by Denys Nevozhai on Unsplash (https://unsplash.com/photos/7nrsVjvALnA)