API Gatewayを使用したフォールバックの実装
November 10, 2023
APIのレジリエンスとは、エラーや高トラフィック、部分的なシステム障害に直面した際に、APIが迅速に失敗するか、障害後も機能し続ける能力のことです。これには、リトライ、タイムアウト、サーキットブレーカー、フェイルオーバー、フォールバックなどの一般的なAPIレジリエンス設計パターンを実装することが含まれます。API Gatewayを使用したフォールバックは、APIのプランBです。プライマリAPIサービスが失敗した場合、API Gatewayはトラフィックをセカンダリサービスにリダイレクトするか、事前に定義された応答を返すことができます。この記事では、既存のフォールバック技術の課題と、APISIX API Gatewayを使用してそれらを効率的に実装する方法について探ります。
APISIXを使用したフォールバックの実装
APISIXでフォールバックメカニズムを実装するには、組み込みのアップストリーム優先度機能を使用するか、response-rewriteプラグインを使用して、サービス呼び出しが失敗した場合に事前に定義された応答を返すことができます。以下に、両方のフォールバック方法を設定するためのステップバイステップの例を示します。
前提条件
このガイドでは、以下のツールがローカルにインストールされていることを前提としています:
- 開始する前に、APISIXの基本的な理解があることが望ましいです。API Gatewayとその主要な概念(ルート、アップストリーム、Admin API、プラグイン、HTTPプロトコル)に精通していることも有益です。
- Dockerを使用して、コンテナ化されたetcdとAPISIXをインストールします。
- サービスにリクエストを送信して検証するために、cURLをインストールします。
APISIX Dockerプロジェクトの開始
このプロジェクトでは、事前に定義されたDocker Compose設定ファイルを活用して、APISIX、etcd、Prometheus、その他のサービスを単一のコマンドでセットアップ、デプロイ、実行します。まず、GitHubでapisix-dockerリポジトリをクローンし、お気に入りのエディタで開き、example
フォルダに移動して、プロジェクトのルートフォルダからターミナルでdocker compose up
コマンドを実行してプロジェクトを開始します。
プロジェクトを開始すると、Dockerは実行に必要なイメージをダウンロードします。また、2つの例のバックエンドサービスweb1
とweb2
を実行します。サービスの完全なリストはdocker-compose.yamlファイルで確認できます。
APISIXアップストリーム優先度を有効にしたフォールバック
各アップストリームノードに特定の優先度レベルを設定して有効にすることができます。優先度の高いノードエンドポイントが失敗した場合、API Gatewayは優先度の低いセカンダリノードにトラフィックをリダイレクトできます。すべてのノードのデフォルトの優先度は0で、負の優先度を持つノードはバックアップとして設定できます。
2つのサービスへのルートを作成し、各アップストリームサービスのノードに優先度属性を設定します:
curl "http://127.0.0.1:9180/apisix/admin/routes" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id":"backend-service-route",
"methods":[
"GET"
],
"uri":"/get",
"upstream":{
"nodes":[
{
"host":"web1",
"port":80,
"weight":1,
"priority":0
},
{
"host":"web2",
"port":80,
"weight":1,
"priority":-1
}
]
}
}'
methods
: このルートが一致するHTTPメソッドを指定します。この場合、GET
リクエストに一致するように設定されています。uri
: このルートが一致するパスです。したがって、/get
へのGET
リクエストはこのルートによって処理されます。nodes
: バックエンドサーバーの配列です。配列内の各オブジェクトは、host
、port
、weight
を持つサーバーを表します。weight
はロードバランシングに使用されます。この場合、両方のサーバーのweight
は1
で、通常はトラフィックを均等に共有することを意味します。priority
: これは2つのノード(web1
、web2
)の追加設定です。priority
フィールドは、ノードが選択される順序を決定するために使用されます。優先度の低いノード(より高い負の数)は、優先度の高いノード(より低い負の数または正の数)が利用できない場合にのみ使用されます。
ルートにリクエストを送信したときにweb1
サービスからの応答のみが得られることを確認します:
curl "http://127.0.0.1:9080/get"
次のような応答が表示されるはずです:
hello web1
これは、web1
が最初に実行されたことを意味します。次に、web1
サービスのコンテナを停止して、APISIXがweb2
サービスにフォールバックすることを確認します。
docker container stop example-web1-1
再度ルートにリクエストを送信すると、指定したフォールバックサービスからの応答が得られます。
curl "http://127.0.0.1:9080/get"
hello web2
デフォルトでは、リクエストが最初にサービス1に送られ、利用できない場合にサービス2にフォールバックするまでに60秒かかります。この時間は、Upstreamオブジェクトのtimeout
属性を設定することで変更することもできます。別のフォールバック戦略として、リリース中に新しいバージョンのAPIにバグがある場合、APISIXのトラフィック分割機能を使用して、スタンバイ中の古いバージョンにトラフィックをルーティングすることができます。新しいバージョンに問題がある場合、以前のバージョンにフォールバックします。このフォールバック方法は、Upstreamヘルスチェックともうまく連携します。
APISIX Response Rewriteプラグインを使用したフォールバック
APISIXのresponse-rewriteプラグインを使用すると、クライアントに返す前に応答のステータスコード、本文、ヘッダーを変更できます。これは、アップストリームサービスが失敗した場合にデフォルトの応答を提供するフォールバックメカニズムを実装するのに特に役立ちます。
最初のアプローチに従った場合、Dockerでweb1
サービスのコンテナを再実行します:
docker container start example-web1-1
フォールバックにresponse-rewriteプラグインを使用するには、ルートで設定する必要があります。以下は、curl
コマンドを使用してプラグインを有効にする方法の例です:
curl "http://127.0.0.1:9180/apisix/admin/routes" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id":"backend-service-route",
"methods":[
"GET"
],
"uri":"/get",
"plugins":{
"response-rewrite":{
"status_code":200,
"body":"{\"message\":\"This is a fallback response when the service is unavailable\"}",
"vars":[
[
"status",
"==",
503
]
]
}
},
"upstream":{
"nodes":{
"web1:80":1
}
}
}'
上記の例では、このルートが一致したときにトラフィックが向けられる単一のバックエンドサービス(web1:80
)を定義しました。アップストリームサービス(web1:80
)が503 Service Unavailable
ステータスで応答した場合、response-rewrite
プラグインは応答を200 OK
ステータスとカスタムJSON本文に変更します。これにより、アップストリームサービスが利用できない場合にフォールバック応答が作成されます。
"vars": [["status", "==", 503]]
: この条件は、応答の元のステータスコードが503 Service Unavailable
の場合にのみプラグインがリライトを適用するように指示します。
ルートにリクエストを送信すると、変更された応答が得られるはずです:
curl "http://127.0.0.1:9080/get"
{"message":"This is a fallback response when the service is unavailable"}
フォールバックメカニズムの実装における課題
フォールバックは、レジリエントなシステム設計の重要なコンポーネントです。しかし、誤って実装されると、さらに多くの問題を引き起こす可能性があります。フォールバック戦略について議論する際、単一マシン環境と分散システムの間で直面する課題は異なる場合があります。APISIXを使用してそれらを回避する方法を理解するために、例を挙げてそれらを確認しましょう。
フォールバックロジックのテストの難しさ
単一マシンのコンテキストでは、データベースの障害などのアプリケーション障害条件を正確にシミュレートするのは困難です。分散システムでは、複数のマシンとサービスが関与するため、フォールバック戦略のテストはさらに複雑になり、すべての可能な障害モードを再現するのが難しくなります。たとえば、ローカルサーバー上のAPIは、データベースが到達不能な場合にキャッシュされた応答にフォールバックします。このシナリオをテストするには、データベースのダウンタイムをシミュレートする必要がありますが、これは通常のテストの一部ではないため、実際の本番負荷下でフォールバックコードがテストされない可能性があります。
APISIXは、フォールバック条件を含むさまざまなシナリオをシミュレートするためにトラフィックをルーティングするように設定できます。これにより、制御された条件下でフォールバックロジックをより現実的にテストし、フォールバックサービスが本番トラフィックを処理できることを確認できます。
フォールバック自体が失敗する可能性
フォールバックソリューションが期待どおりにレジリエントでない場合、それが呼び出されたときに発生する増加した負荷に耐えられず、連鎖的な障害を引き起こす可能性があります。また、効率の低いサービスへのフォールバックは、応答時間と負荷を増加させ、システム全体の速度低下や停止を引き起こす可能性があります。たとえば、リモートロギングサービスが利用できない場合にローカルファイルシステムにログを書き込むフォールバックがあるAPIは、同期ファイルI/O操作によりパフォーマンスが低下する可能性があります。
APISIXを使用すると、重要なリクエストが最初に処理されるようにトラフィックを優先順位付けできます。これにより、フォールバックサービスが過負荷になり、システムのパフォーマンスが悪化するのを防ぐことができます。
フォールバックには運用リスクがある
フォールバックを実装すると、プライマリと同期されていないセカンダリデータベースなどの新しい障害点が導入され、データの不整合が発生する可能性があります。
APISIXのロギング、メトリクス、トレースなどの監視機能を使用すると、プライマリとフォールバックサービスの健全性とパフォーマンスを監視できます。このリアルタイム監視により、フォールバック戦略に関連するリスクを特定して軽減することができます。
フォールバックには潜在的なバグがある
フォールバックコードパスには、特定の障害条件下でのみ発生する非アクティブなバグが含まれている可能性があり、これらは頻繁に発生しないため、予測が難しく、数ヶ月または数年後に発見される可能性があります。たとえば、IDサービスが停止している間に異なる認証方法に切り替えるAPIのフォールバックメカニズムには、フォールバックがトリガーされたときにのみ現れるバグが含まれている可能性があり、これはまれなイベントである可能性があります。
APISIXは継続的なA/Bテストとカナリアリリースをサポートしており、チームは本番環境で少量のトラフィックを使用してフォールバックパスをテストできます。この継続的な露出により、潜在的なバグが重大になる前に発見されることがあります。
フォールバックは頻繁に使用されない
フォールバックメカニズムは頻繁に使用されないため、トリガーされたときに期待どおりに動作しない可能性があります。たとえば、地理データを提供するAPIは、動的データソースが利用できない場合に静的データセットにフォールバックする場合があります。このフォールバックがまれに使用される場合、アクティブ化されたときに古い情報を提供する可能性があります。これは、定期的に更新またはテストされていないためです。
一方、APISIXを使用すると、動的ルーティングを設定し、定期的にトラフィックの一部をフォールバックサービスにリダイレクトすることができます。これにより、フォールバックパスが定期的に実行され、使用可能な状態に保たれます。
結論
フォールバックは、APIに問題が発生した場合の安全網です。APISIXのアップストリーム設定またはresponse-rewriteプラグインを使用することで、開発者は、システムが機能し続け、ユーザーとの信頼を維持するための思慮深くユーザーフレンドリーな応答を提供できます。重要なのは、潜在的な障害点を予測し、状況下で最良のエクスペリエンスを提供するフォールバックを設計することです。