同期ウェブ API と非同期ステートフル API の違い
Google Cloud Japan Team
※この投稿は米国時間 2021 年 9 月 14 日に、Google Cloud blog に投稿されたものの抄訳です。
この記事の目的は、統合ソリューションであることが多い非同期ソリューションと、API 主導のソリューションである同期ソリューション間のアーキテクチャ面の決定を促すユースケースを識別することです。ほとんどの場合、これは二者択一の決定ではありません。多くのソリューションは、いくつもの流動的な要素に依存しています。その複雑さを解消するには、多くの場合、同期ソリューションと非同期ソリューションの併用が最良のアプローチとなります。さらに、従来の統合システム(非同期であることが多い)で解消する問題は、API 管理で解消する一連の問題とは種類が異なります。
歴史: サービス革命前の API
アプリケーション プログラミング インターフェースの略である API は、簡単に言うと、2 つのアプリケーション間のやり取りを仲介する橋渡しの役割を担います。この API がアプリケーション間で実行できる呼び出しとその方法を定義し、すべてをコントラクトにまとめます。多くの場合、このコントラクトでは、API を介して流れるデータ構造も定義されます。
ウェブ API は、アドホックの標準としてシステムの拡張性から誕生し、デベロッパーは API を介してライブラリや他のシステムを使っていました。API は、ソフトウェアの再利用というソフトウェア エンジニアリングの力強いコンセプトの普及に貢献しました。このコンセプトが進化し、インターネットを背景にソフトウェアの再利用の実装が進みました。つまり、パブリック エンドポイントを持つ各サービスに再利用される可能性が生まれ、分散システムが形成されました。
ウェブ API に関しては、いずれのコンソーシアムや標準化団体も、ウェブ API のコンセプトとその基盤となるプロトコルを指定していません。ただし、ウェブ API のプラクティスは、通信に利用でき、その目的に HTTP プロトコル(通常はバージョン 1.1)を使用する一般に公開されたエンドポイントに基づいています。また、ウェブ API では、データの交換にリクエストとレスポンスのメッセージング メカニズムが使用され、その中で発信者(クライアント)がサービス プロバイダにリクエストを送ってメッセージを開始します。これにより、クライアントにレスポンスが返されます。通常、リクエストとレスポンスのペイロードは、XML と JSON のデータ形式です。
2000 年代初め、サービス指向アーキテクチャが企業向け分野で盛り上がりを見せました。そして 2010 年代に入ると、REST が注目されるようになりました。このような、異なるアプリケーションをつなぐネットワークベースのやり取りには、SOAP(SOA から登場)であっても REST であっても、共通点が一つあります。それは、ステートレスだということです。
ただし、ステートフルな統合も同様に使われていました。異種のシステムをつなぎ、システム間でペイロードとプロトコルを変換するために、統合ソフトウェアが使われていたのです。さらに、これらのシステムの多くが、HTTP だけではエンジニアリングが難しい配信パターンを確保するためのセットアップのステートフルな特性を使っていました。保証された 1 回の配信、最低 1 回の配信、そして、イベントのプロデューサーがイベントの受信者やその数さえ把握していない場合のトピックのストリーミングなどです。
ステートフル非同期とステートレス同期の違い
インターネット、そして特にウェブおよびモバイル インターネットは、ステートレスな HTTP ベースの API を使って成長しています。私たちがモバイル デバイスで行うほぼすべてのことが、API が仲介するクライアント / サーバーモデルに基づいています。この API はステートレスです。つまり、基盤となるインフラストラクチャの要件をオンデマンドでスケールアップおよびスケールダウンでき、膨大な接続プールを処理するためのポイントは不要です。
さらに、これらの HTTP API のすべてが迅速に仲介を行うため、同期トランザクションになります。中には時間がかかるトランザクションもあるため、そのニーズに対応できるよう調整されました。皆さんの中に、リクエストを受け入れてレスポンスで「202 Accepted」と返すアプリケーションを記述したことがある人はいるでしょうか。実際には非同期トランザクションと思えるほどの、長時間の処理プロセスが開始されます。
前の例を使って、少し掘り下げてみましょう。モバイル デバイスの世界では、迅速なレスポンスが求められます。202 を返すことは適切なレスポンスであり、リクエストが「保留中」または「進行中」であることを示すペイロードを伴う場合もあります。そのプロセスは、サーバーサイドのデベロッパーが到達できない、多数のダウンストリーム要因に依存している可能性があります。たびたびオフラインになるダウンストリーム アプリケーションを考えてみてください。受信した命令をすべてトラッキングするキューを作成すべきかも知れませんが、当面は一つずつ試行錯誤の繰り返しになります。そのバックエンドがオンラインになれば、問題ありません。キューの 1 つ目、2 つ目、3 つ目のアイテムが成功すれば、失敗するまで続けます。その時点で、試行に関してバックオフできます。この種のインタラクションでクライアント / サーバー型のアプリケーションを構築すると、散々な目にあいます。しかし、現実の世界でそのようなニーズが実際にないとは限りません。
API 管理またはシステム統合を使うケース
API 管理規範では、非同期ステートフル API ではなく同期 HTTP API に焦点を当てています。この決定は主に、ワールド ワイド ウェブでの HTTP API の出現に関連する歴史的な理由に基づいています。現在 WWW モデルは、HTTP を通じてリソースにアクセスするための最も一般的な標準です。このモデルの普及は、分散アプリケーションの開発に影響を与えた基礎の構築に貢献し、インターネットと WWW モデルのインフラストラクチャを再利用した API の展開につながりました。これは、HTTP API のたとえばプログラミング言語のライブラリなどで使用され、今ではリクエスタがインターネット上でアクセスできるサーバー情報へのエンドポイントになっています。
一方、システム統合の規範では、同期ウェブ API と、エンタープライズ サービスバス(ESB)で構築される非同期ステートフル API の両方に焦点を当てています。ESB は JMS や AMQP などの一連の異なるプロトコルをサポートするため、ESB に API を実装すると、HTTP への依存度が低くなります。
採用する規範の選択は、実装する必要があるユースケースの特性によって決まります。
API 管理規範の価値提案
API 管理規範は、デジタル経済においてアクティブなプレーヤーになり、そのことによって認識されることを戦略上の目標にしている企業に適しています。この戦略を追及する企業は、公開または非公開 API を公開してデベロッパー コミュニティに働きかけることに前向きです。当然のことながら、再利用されることでアプリの価値を高めたいと考えているからです。たとえば、位置情報サービスに基づいたアプリを開発するすべての企業に Google マップのようなサービスの実装が求められるわけではありません。Google マップの API を再利用すれば、同じようなサービスを再構築することなく価値を集約できます。
API 管理規範は、この種の状況に対する直接的な取り組みとして、企業の API 公開を許可する一連のコンセプトを定義しています。主に以下の点が考慮されています。
API デベロッパーのスムーズなオンボーディング
これらのデベロッパーによる API 使用状況のトラッキング
インターネット経由での API へのアクセスのしやすさ
API 管理において、サードパーティが提供する API を使用する必要があるアプリ デベロッパーは、API の理解、試用、サブスクライブ、活用がスムーズにできなければなりません。成熟したデベロッパー ポータルやフリーミアム料金プラン、ガイドラインなど、API を使ってさまざまな結果を確かめ、API 活用のエキスパートになるための多彩なメカニズムがデベロッパーには必要です。これらのメカニズムがあることで、一時的に API を探索していただけのデベロッパーを惹きつけ、高品質なサービスには支払いをいとわない顧客となるデベロッパーにすばやく変えることができるはずです。つまり API 管理規範は、このようなポジティブなエクスペリエンスに貢献する可能性があるすべてのメカニズムの使用を想定しています。
API プログラムの成功は、API の実装と一般公開の有無だけでなく、API の消費トレンドを理解しているかどうかで決まります。企業はそれぞれの API を使用しているアプリ デベロッパーの人数と生成されている API 呼び出しの件数に加え、フリーミアム モデルから料金プランに変更したアプリ デベロッパーから生じた収益とその頻度を知る必要があります。自社の API が他と比べてどのくらい人気があるかを把握するにはこの情報が不可欠で、ここからインサイトが得られます。意思決定者はより多くの情報に基づいて、成功している API と API 製品をそうでないものよりも優先して使用するという決定を下すことができます。このような情報は、通常 Apigee などの API 管理プラットフォームによって自動的に収集され、ダッシュボード形式で見やすく表示されます。このダッシュボードは、社内の API プログラムの現実と特性の違いに合わせてカスタマイズすることもできますが、API プログラムの一般的な成功を決定するメカニズムが必要だという本来の意図は変わりません。このように API 管理規範では、デベロッパーによる使用状況に関する API トラッキング メカニズムの実装および使用を推奨しています。
最後に、企業の戦略が不特定多数のアプリ デベロッパーに訴求し、API を提供することであるならば、デベロッパーにとって使いやすく、障壁となりうる技術コンポーネントの導入を必要としない API でなければなりません。これが、API 管理規範で標準的かつ普及している HTTP を通信プロトコルとして使い、ウェブ API を構築した主な理由です。このプロトコルに慣れているウェブ デベロッパーにとって、ウェブ API を使って API デベロッパーになることは簡単なはずです。そのような理由から、API 管理規範では API 管理プラットフォームをとおして、HTTP がサポートするリクエストとレスポンスのメッセージング パターンのみに依存する API を同期ウェブ API として公開しています。
システム統合および非同期規範の価値提案
システム統合の世界は、システム間の技術通信を戦術的に解決することに主に焦点を当てています。エンゲージメントのためのマーケットプレイスを作るのではなく、通常システム内部にのみ付随する一連の問題を解消し、コアとなるビジネス ロジックとしっかり結びついたインターフェースを定義することが目的です。内部ネットワークには、さまざまなプロトコルやバックエンド、レイテンシが存在します。この複雑さの原因をすべて把握しつつ、簡単に導入できる安定したサービスをできるだけ簡単に作成するための方法が必要です。まず思い浮かぶのはキュー、トピック、ストリームに依存するメッセージング システムですが、この分野には優先度の高い特有の項目があります。以下は、いくつかを抜粋したリストです。それぞれの項目が、その直前の項目を基にしています。一つずつ見ていきましょう。
プロトコルの変換
トランザクションの整合性
例外処理
プロトコルの変換
API 開発の中心は HTTP ですが、大規模な企業ではあらゆる種類のプロトコル、バージョン、ソケットに対する懸念が存在します。統合ソリューションでは、そのようなニーズを置き換えるゲートウェイとステートフルなシステムを提供することで、ニーズの把握を試みます。HTTP 経由でクライアント通信を許可するサービスがあるとします。しかし、そのサービスは RabbitMQ でホストされているバックエンド キューに接続された永続的なランタイムや、Kafka でホストされたトピックを使用しているかもしれません。特定のテーブルで更新や挿入を探すカスタム トリガーとの統合がある場合も考えられます。そのテーブルにどんな変更が加えられても、システムはそのイベントを取得し、キューまたはトピックに送信されるメッセージ形式で新しいイベントを発行します。これによって、DB がメッセージに変換され、DB のロジックを理解する必要のないシステムに、シンプルにトピックをサブスクライブする機能を提供します。
gRPC
gRPC については簡単に説明します。gRPC は http/2 に依存し、同期パターンと非同期パターンの両方で機能できるようにします。HTTP ベースのプロトコルであることに変わりありませんが、データベースとクエリシステムへのウェブシステムの統合よりも、デベロッパーによるサービス作成と使用に大きく関わります。そのために gRPC または RESTful API を使うことができ、基本的な原則は同じです。gRPC の詳しい内容は、このドキュメントの範囲外です。
トランザクションの整合性
API はファイア アンド フォーゲット スタイルのステートレスな HTTP リクエストを基にしています。一方の統合は、多くの場合ステートフルなバックエンド システムに接続しつつ、分散型トランザクションを処理するトランザクション ラッパーを処理します。典型的な例として、クライアントが決済トランザクションを行い、別の口座(銀行が違う場合もあります)への資金移動をするパターンを想定してください。振込先口座への振り込みが失敗した場合、元の口座からの引き落としは決して発生してはいけません。これがトランザクションの整合性であり、このケースでは分散型トランザクションです。この種の低レベルのロジックを API ゲートウェイで処理することはアンチパターンであるだけでなく、HTTP 経由で通信できないシステムの関与を確実に引き起こすことになります。これらのプロトコルに対応するだけでなく、他のシステムの上にトランザクション システムを構築する別のシステムが必要です。さらに、必要に応じて障害時にロールバックできるようにするのがよいでしょう。
例外処理
最後に、前の 2 つのトピックを合わせた例外を取り上げます。前の例では、分散型トランザクションと、問題が発生した場合のロールバック要件について考えました。しかし、システムで再試行し、また失敗しても最大 5 回は再試行したい場合はどうすればよいでしょうか。それだけでなく、次の再試行までの時間を長くしたい場合、つまりバックオフ機能を使いたい場合はどうでしょう。当然のことながら、これは単一の HTTP リクエストのライフタイムでは達成できず、このようなトランザクションで構成されるシステムの構築は非同期の本質そのものです。非同期システムの特徴には、永続的な性質と、システムが受信イベントに反応する点が挙げられることがよくあります。どちらもその通りですが、再試行の構築、適切な例外処理、そしてバックオフ機能も同じく重要な特徴です。
実際の例
API が対処しようとするニーズ、統合および非同期システムが対処する分野を考慮すると、その両方が適用されるシナリオは実際にどのようなものでしょうか。下の例について考えてみましょう。先ほどと同じくすべてを網羅したものではありませんが、両方のタイプのシステムの組み合わせ方がわかるはずです。


フロントエンド クライアント
図のとおり、外部クライアントは携帯電話です。デベロッパーが API を使用して開発したアプリだと考えてみましょう。API GW はこのアプリケーションを一意に特定し、アプリケーションのスロットリングを行い、分析を収集します。さらに、独自のキャッシュ データベースを更新する軽量の DB サービスに接続されています。新しい命令(ここではサービス命令と呼びます)が入ってくると、システムがキャッシュ DB に行を書き込み、アプリケーションに新しい命令が保留中であることを知らせる本文付きの 202 を返します。
最初の統合
キャッシュ DB をリッスンし、新しいサービス命令をピックアップする統合パターンがセットアップされています。統合をトリガーする新しいサービス命令が生じると、トピックでホストされている「新しいサービス命令」トピック(このトピックと他のトピックをホストする Kafka クラスタとします)にイベントが発行されます。
2 つ目の統合
先ほどのように、イベントを待機している別の統合セットアップがあります。今回の統合は、「新しいサービス命令」トピックへの新しいイベントの発行を待っています。新しい命令が発生すると、その統合がバックエンドのデータベースを更新し(新しい命令を適切にセットアップ)、他のコンポーネントに通知を送信します。さらに、API リクエストをデータレイク サービスに送り、データレイク サービスがデータ ウェアハウスを更新します。この流れのいずれかでエラーが発生すると、再試行が必要となります。最終的に必要であれば、トランザクションのロールバックも行われます。成功すると、新しいメッセージが別のトピック「更新済みサービス命令」に発行されます。
再び最初の統合
最初の統合は「更新済みサービス命令」トピックの更新もリッスンします。ここでは、完了したサービス命令 ID を含む更新が受信されます。続いて、システムはキャッシュ DB を新しい情報に更新し、「保留中」ステータスを「進行中」に変更します。モバイル クライアントが再度ステータスを確認すると、キャッシュ DB に保存され、DB サービスによってホストされている更新済みの「進行中」ステータスを取得します。
非同期と同期の併用
ここで、さらに複雑なパターンを想定することもできます。データレイク サービスが「新しいサービス命令」イベントに関心のある唯一のダウンストリーム サブスクライバーではないことも考えられます。同様に、DB サービスが「更新済みサービス命令」イベントに関心のある唯一のサービスではない場合もあるでしょう。保留中のサービス命令を作成し、通知を受け取るまでユーザーによる更新確認を許可しないアプリケーションを考えてみてください。プッシュ通知を送信する別のサービスがあるケースも考えられます。これらの非同期および同期イベントをつなぎ合わせることで、簡単にスケールおよび拡張できるだけでなく、デベロッパーにとって魅力的で、ビジネス ロジックのニーズとシンプルな API コントラクト要件を適切に区別するシステムを構築します。
結論
アーキテクチャ面の決定では、同期パターンまたは非同期パターンが促されることが多いのですが、完全なエンドツーエンドのソリューションはその両方を活用することが少なくありません。とは言え、これらのパターンについて理解し、そのパターンに依存するシステムとのデベロッパーの関わり方を理解することが重要なことに変わりはありません。
多くの場合、非同期システムを使えば、プロトコル間の変換、ステートフル ソケットの処理など、統合の問題が解消されます。このシステムは、そのような特定のニーズに対応するために構築されています。通常、API 管理システムと API は、デベロッパーができるだけ簡単に API を見つけて使えるように作られています。さらに、API は通常の場合ステートレスで、HTTP プロトコルのみを使う RESTful API です。複雑なアーキテクチャでは両方のタイプのプラットフォームが必要であり、それぞれを使うべきケースとその方法について理解しておくことは、洗練されたシステム設計に不可欠です。また、それぞれのシステムで想定されることを理解することも重要です。統合の課題を API 管理で解決しようとしてはいけません。同様に、API 管理の課題を従来の統合システムで解決しようとすると、デベロッパーのエンゲージメントと動的なスケーリングに関して苦労することになるでしょう。
- Jordan Janeiro- Geir Sjurseth