このトピックでは、Service Mesh (ASM) で HTTP 503 ステータスコードが返される一般的なシナリオと、対応する解決策について説明します。
HTTP 503 ステータスコードの断続的な発生
シナリオ 1:メトリックカスタマイズ機能を使用してパーソナライズされた構成を実行しています。カスタムメトリックの構成を変更するたびに、ログに少数のリクエストに対して HTTP 503 ステータスコードが返されたことが示されます。
原因
メトリックカスタマイズ機能のメカニズムは、istio.stats
構成を更新するための Envoy フィルターを生成することです。この構成は、Listener Discovery Service (LDS) を使用して Envoy リスナーで有効になります。 Envoy リスナーの構成が変更されると、既存の接続は切断されます。接続がリセットまたは閉じられるため、転送中の対応するリクエストに対して HTTP 503 ステータスコードが返されます。
解決策
アップストリームサーバーが接続を閉じると、表示される HTTP 503 ステータスコードはアップストリームサーバーによって送信されません。代わりに、アップストリームサーバーによる切断への応答として、クライアントサイドカープロキシによって返されます。
Istio のデフォルトの再試行構成には、「アップストリームサーバーが接続を閉じる」というシナリオは含まれていません。Envoy プロキシの再試行条件の中で、Connection Reset はこのシナリオのトリガー条件を満たしています。したがって、対応するサービスのルートに対して再試行ポリシーを構成する必要があります。具体的には、仮想サービスの再試行ポリシー構成に Reset のトリガー条件を追加する必要があります。
次のコードは構成例を示しています。この構成は、Ratings サービスに対してのみ有効です。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings-route
spec:
hosts:
- ratings.prod.svc.cluster.local
http:
- route:
- destination:
host: ratings.prod.svc.cluster.local
subset: v1
retries:
attempts: 2
retryOn: connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes,reset,503
FAQ
サイドカープロキシのデフォルトの再試行メカニズムが有効にならないのはなぜですか?
次のセクションでは、サイドカープロキシのデフォルトの再試行をトリガーする条件を示します。再試行はデフォルトで 2 回実行されます。上記のシナリオは再試行条件の対象外です。したがって、再試行メカニズムは有効になりません。
"retry_policy": {
"retry_on": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
"num_retries": 2,
"retry_host_predicate": [
{
"name": "envoy.retry_host_predicates.previous_hosts"
}
],
"host_selection_retry_max_attempts": "5",
"retriable_status_codes": [
503
]
}
connect-failure: 接続エラーを示します。
refused-stream: HTTP/2 ストリームに対して
REFUSED_STREAM
エラーコードが返されたことを示します。unavailable: gRPC リクエストに対して
unavailable
エラーコードが返されたことを示します。cancelled: gRPC リクエストに対して
cancelled
エラーコードが返されたことを示します。retriable-status-codes: リクエストに対して返された
status_code
が、retriable_status_codes
構成で定義されているエラーコードと一致することを示します。
Envoy プロキシの最新バージョンのすべての再試行条件の詳細については、次のドキュメントを参照してください。
Router: 既存の HTTP リクエストの再試行条件 (HTTP/2 および HTTP/3 を含む)
x-envoy-retry-grpc-on: gRPC 固有の再試行条件
シナリオ 2:構成を変更していない場合でも、HTTP 503 ステータスコードが断続的に返されます。この問題に関する特定のルールは見つかりません。
HTTP 503 ステータスコードが断続的に返されますが、トラフィックが多い場合はより頻繁に発生します。一般に、この問題はサイドカープロキシの受信トラフィックで発生します。
原因
サイドカープロキシのアイドル接続のタイムアウト期間が、アプリケーションのタイムアウト期間と一致していません。サイドカープロキシのアイドル接続のデフォルトのタイムアウト期間は 1 時間です。
サイドカープロキシのアイドル接続のタイムアウト期間が長すぎるのに対し、アプリケーションのタイムアウト期間が比較的短い。
アプリケーションはアイドル接続を終了しましたが、サイドカープロキシは接続が終了していないと見なしています。この時点で、サイドカープロキシに新しいリクエストが送信されると、HTTP 503 ステータスコード (response_flags=UC) が報告されます。
サイドカープロキシのアイドル接続のタイムアウト期間が短すぎるのに対し、アプリケーションのタイムアウト期間が比較的長い。
この条件下では、HTTP 503 ステータスコードは報告されません。このシナリオでは、サイドカープロキシは前の接続が閉じられたと見なし、直接新しい接続を作成します。
解決策
解決策 1:宛先ルールで idleTimeout を構成する
この問題の原因は、両端の idleTimeout 設定の不一致です。この問題を解決するには、宛先ルールで idleTimeout を構成することをお勧めします。
idleTimeout 設定は、サイドカープロキシの発信トラフィックと受信トラフィックの両方に有効です。クライアントにサイドカープロキシがない場合、idleTimeout 設定も有効になり、HTTP 503 ステータスコードの報告を効果的に削減できます。
構成の推奨事項:idleTimeout 設定はサービスによって異なります。 idleTimeout パラメーターが短すぎる期間に設定されていると、接続数が多すぎます。このパラメーターは、サービスの実際の idleTimeout 期間よりわずかに短い期間に設定することをお勧めします。
解決策 2:仮想サービスで再試行を構成する
再試行により接続の再確立がトリガーされ、この問題を解決できます。詳細については、「シナリオ 1 の解決策」を参照してください。
リクエストが非冪等リクエストの場合、再試行はリスクの高い操作です。仮想サービスで再試行を構成する場合は注意してください。
シナリオ 3:サイドカープロキシコンテナのライフサイクルが不適切に構成されている状況下で、HTTP 503 ステータスコードが断続的に返されます。
原因
サイドカープロキシコンテナのライフサイクル設定が不適切なためにポッドが再起動されると、HTTP 503 ステータスコードが断続的に返されます。
解決策
詳細については、「サイドカープロキシのライフサイクル」を参照してください。
HTTP 503 ステータスコードの必然的な発生
シナリオ 1:アプリケーションが localhost をリッスンしています。
原因
クラスター内のアプリケーションが localhost をリッスンしている場合、クラスター内の他のポッドはアプリケーションにアクセスできません。
解決策
クラスター内の他のポッドにアプリケーションを公開することで、この問題を解決できます。詳細については、「localhost をリッスンしているクラスターアプリケーションをクラスター内の他のポッドに公開するにはどうすればよいですか?」を参照してください。
シナリオ 2:サイドカープロキシがポッドに挿入された後、ポッドのヘルスチェックは常に失敗し、HTTP 503 ステータスコードが報告されます。
原因
ASM で相互トランスポート層セキュリティ (mTLS) を有効にすると、kubelet がポッドに送信するヘルスチェックのリクエストはサイドカープロキシによってインターセプトされます。 kubelet が必要な TLS 証明書を提供できない場合、ヘルスチェックは失敗します。
解決策
トラフィックがサイドカープロキシにリダイレクトされないポートを構成できます。詳細については、「サイドカーの挿入後に有効なヘルスチェック情報が表示されないのはなぜですか?」を参照してください。