HN 日本語サマリー

← 一覧へ戻る
インフラ・DevOps

Uberがリトライストームから保護する方法

How Uber Protects Against Retry Storms (uber.com)

14 pointsby iscmt9 コメント

要約

Uberは、サービス間の依存関係が深まり、単一の障害が連鎖的な障害を引き起こす「リトライストーム」問題に対処するため、コンテキストを認識するエラー処理メカニズムを開発しました。従来のリトライ設定は手動で可視性が低く、問題が悪化する原因となっていました。新しいシステムは、エラーの原因を特定し、リトライをより賢く制御することで、インフラストラクチャの安定性とユーザーエクスペリエンスを向上させます。

全文翻訳

2026年9月17日Uberがリトライストームから保護する方法DMDeepanshu MehndirattaSenior Staff EngineerASAlok SrivastavaPrincipal EngineerVDVibhor DhingraSr Software Engineer1+この記事を共有するFacebook LinkedinXソーシャルリンクはじめにリトライストームは、歴史的にビジネスオペレーションとブランドの信頼に影響を与えています。リトライ設定のチューニングとリトライバジェットは、サービスレベルで意味のある緩和を提供しますが、それらは手動で設定されており、深い依存関係チェーンとファンアウトパターンによって引き起こされるクロスサービス増幅の可視性が欠けています。その結果、スタックの奥深くにある単一のサービス障害によってトリガーされるドミノ効果からインフラストラクチャを保護することが困難になる場合があります。主な理由は、現在のリトライ動作がコンテキストを認識していないことです。リトライが何回発生するかを制御できても、それらがいつ発生するかを正確に制御することはできません。これは、サービスによって生成されたエラーと、単にそれを介して伝播されたエラーを確実に区別するという課題から生じます。その結果、リトライは条件付きではなく均一に適用されます。このアプローチは、一時的または低レートの障害には有効です。しかし、中程度または重度の劣化中には、逆効果になります。すでに苦労しているサービスに対して積極的にリトライすると、負荷が増加し、障害が加速し、アップストリームの依存関係全体でリトライトラフィックが増幅されます。局所的な障害として始まったものが、急速にスタック全体のインシデントにエスカレートする可能性があります。最終的には、エンドユーザーエクスペリエンスを低下させ、最悪の場合、完全に破壊することになります。ダウンストリームサービスからのエラーコードをアップストリームに変換してリトライのコンテキストを提供できると主張する人もいるかもしれません。理論的には可能ですが、Uberでは大規模なファンインとファンアウト、進化するコールフロー、頻繁な適応変更の必要性により、このアプローチはスケーリングしません。したがって、エラーをより効率的に処理するために、共有インフラストラクチャにコンテキストを認識するメカニズムを開発しました。この記事では、そのメカニズムについて説明します。背景図1に示す単純なコールチェーンを検討してください。ここで、NodeAに到着するリクエストの総数はηです。推論により、ノードB、C、D、E、F、およびGはすべて、定常状態(ノードがエラーを発生しない場合)でηのリクエストを処理します。図1:1:1のファンアウトを持つコールチェーン。ノードは、着信リクエストごとにダウンストリームを正確に1回呼び出します。サービスDがエラーを発生し始め、各サービスが1回のリトライ(通常の試行1回と、ダウンストリームが失敗した場合のもう1回の試行)に設定されている場合、各ノードが処理するリクエストの総数を見てみましょう。図2:サービスがエラーを発生するコールチェーン。ノードABCDEFG深度0123456処理リクエスト数η 2×η 4×η 8×η 8×η 8×η 8×ηこれは、単純な式に要約できます。各ホップでリトライ数Rが同じであると仮定します。δはコールチェーン内のノードの深度を示します。ノードがエラーを作成または通過する場合にノードが処理するリクエスト数:Rδ×ηリトライバジェットリトライバジェットを導入することで最適化できます。各ホップで同じリトライバジェットBを表すと仮定します。新しい式は次のようになります:(1+B)δ×η次に、リトライバジェットが10%の場合の処理リクエスト数を見てみましょう:ノードABCDEFG深度0123456処理リクエスト数η 1.1×η 1.21×η 1.33×η 1.33×η 1.33×η 1.33×η上記の例では、エラーはNodeDで発生し、リトライをNodeDとNodeC間のエッジにのみ制限し、NodeAとNodeBがこのエラーに対してリトライするのを完全に制限すると、NodeD、NodeE、NodeF、およびNodeGに過負荷をかけずに、コールパスの同様の可用性を保証できます。エラーの所有権同じリトライバジェットの例を、エラーが発生するNodeCからNodeDへのエッジを制限しながら使用します。ノードABCDEFG深度0123456処理リクエスト数η η η 1.1×η 1.1×η 1.1×η 1.1×ηここでは、DからリーフノードGまでのすべてのノードが処理するリクエストの総数をベースラインの10%超に制限しますが、最初に戻されたエラーの最大10%で少なくとも1回の試行を許可します。しかし、NodeCから見たNodeDの可用性についてはどうでしょうか?さまざまな可用性シナリオの数値を実行し、リトライ後の可用性を計算してみましょう。ベース可用性%ベースエラー率%リトライバジェットリトライ後のエラー率%リトライ後の可用性%99.90.110%0.000199.999999110%0.0199.9995510%0.2599.75901010%199802010%1288703010%2377上記の表に示すように、呼び出し先ノードでの可用性の低下が10%までであれば、1回の試行でも呼び出し元ノードから認識される可用性を99%まで向上させるのに役立ちます。これを超えると、リトライバジェットのためリトライされないリクエストの大部分があるため、認識される可用性は大幅に低下します。この計算は、呼び出し先からのエラーが独立しており、リトライが回復につながると仮定しています。しかし、サービス過負荷、データベースホストの障害、データベース過負荷、シャーディングの問題など、多くの実世界のシナリオでは、リトライがあってもリトライの確率は高くなります。これは、呼び出し先へのリトライが常に呼び出し元への認識される可用性を高めるという考えと矛盾します。また、この直感がエラーの所有権の基礎を形成しています。サービスからのエラー率が高い期間中、エラーはランダムである可能性が低く、より多くのリトライから利益を得られない可能性があり、代わりにさらなる劣化の原因となる可能性があります。アーキテクチャソリューションは、症状と原因の類推を使用して説明できるエラーの所有権を確立することです。サービスがリクエストを処理するためにN個のアウトバウンドを呼び出し、アウトバウンドエラーが発生してエラーを返す場合、そのサービスによって返されるエラーは単なる症状です。同時に、サービスのコンテキストでは、原因はダウンストリームからの着信エラーです。しかし、サービスがリクエストを処理する際に出力のエラーが発生せず、それでもエラーを返す場合、サービスが返されたエラーの原因であり、所有者です。次のセクションでは、これを活用できる可能性のあるソリューションについて説明します。単純な相関関係エラーの所有権の主張サービス依存分析ソリューションを使用して、インバウンド障害とアウトバウンド障害を相関させ、図3に示すルールセットを使用してエラー主張を作成または却下します。図3:エラーの所有権を主張するための決定ロジック。エラーの所有権を持つリトライ呼び出し元は、図4に示すロジックを使用して、リクエストをリトライすべきかどうかを判断します。図4:リトライを許可するための決定ロジック。エラー主張ヘッダーの欠落というシナリオは非協力的な環境ですが、ダウンストリームサービスがサービス依存分析ソリューションを持っておらず、アウトバウンドとインバウンドのエラーを相関させることができないために発生する可能性があります。または、ダウンストリームサービスはコンテキスト伝播が不足しており、アウトバウンドとインバウンドのエラー間の不完全な相関につながります。ここで、ダウンストリームから欠落したエラー主張を見る最初のノードはエラーを解除し、リトライ障害の影響範囲(もはやストームではなくなる)を制限しますが、それでもエラーを返したサービスへの十分なリトライを許可します。決定マトリックス呼び出し先エラー呼び出し元エラー呼び出し先エラー主張呼び出し元はリトライすべきか(リトライミドルウェア)呼び出し元伝播エラー主張なしはいなしなし主張はいはい欠落はいアンクレームはいはい主張済みはいアンクレームはいはい未主張いいえアンクレーム図5:呼び出し元エラーを実証するために使用される3つのノード。エッジA→BおよびB→Cがフェイルクローズであり、ノードCが主張された内部エラーを返した場合、ノードBはCからの主張されたエラーを見てCにリトライすべきです。しかし、リトライが失敗した場合、それはエラーをノードAに伝播しますが、エラーを返す際にそれをアンクレームする必要があります。ノードAは、Bからのエラーとアンクレームされたエラーヘッダーを見て、ノードBへのリクエストをリトライすべきではありません。図6:エラー主張伝播のための決定ロジック。偶然のエラーとサービス依存分析が必要な理由上記の決定マトリックスは、ダウンストリーム呼び出しが失敗した場合や内部サーバーエラーが発生した場合のケースをカバーしています。両方が同時に発生するシナリオも考えられます。図7を参照してください。図7:ノードAが2つのフェイルオープン依存関係、ノードBおよびノードCを持つ例。この例では、ノードBとノードCは両方ともフェイルオープンです。この例では、ノードBとノードCは両方ともフェイルオープンです。