2024年11月のブラックフライデー、当日の午前1時、中国東部の越境EC化粧品3PLのOMSがAPIタイムアウトを大量に吐き出した。当直エンジニアの最初の直感はリトライの追加だった——5秒のタイムアウト後に再送、最大3回試行。午前3時までにチェーン全体が崩壊した:WMSは注文の受領確認を取得できず、TMSは運賃請求書の照会ができず、ピッキングタスクのステータスは40分間未報告のままだった。倉庫は手作業の照合に逆戻りした。これは単発の事故ではない。倉庫システム連携における繰り返しの脚本である。1つのAPIタイムアウトが、善意のリトライによってリトライ嵐へと転がっていく。
現象:1つのタイムアウトがチェーン全体の崩壊に雪だるま式に膨らむ仕組み
あの夜のタイムラインは示唆に富む。ブラックフライデーの深夜セールでOMSの注文量が急増し、WMSの注文受付APIは遅くなり、5秒のタイムアウトが出現した。WMSのリトライロジックはハードコードされていた:タイムアウト時に即再送、3回試行。しかし下流のTMS運賃請求書照会も同じピーク負荷に晒されており、WMSのリトライトラフィックがTMSへのクエリ量を数倍に膨らませた。TMSは屈し、キャリアの追跡APIを叩きまくり、レートリミッターが作動した。スロットルされるとコールバックがキューに滞留し、WMSのピッキングタスクのステータス更新はすべて詰まった——1つのリンクのタイムアウトが、各層のリトライによってホップごとに増幅され、チェーン全体が落ちるまで続いた。
公開されているシステム設計の文献により、この増幅を定量化できる。呼び出しチェーンが4ホップ(OMS → WMS → TMS → キャリアAPI)で、各ホップがタイムアウト時に2回リトライすると仮定する。最悪の場合、最下流のサービスは通常のリクエスト量の 3 × 3 × 3 = 27倍に直面する。200 QPSで健全だったAPIが突然 5,400 QPS に直面する——一方、キャリアのレートリミットは通常ピークのわずか2–3×に設定されている。これは概算だが、あの夜TMSが最初に落ちた理由を説明する:「少し多い」トラフィックではなく、桁違いの圧殺だった。
もう1つの事例も同様に注目に値する。ある3PLのTMSはキャリア追跡APIをタイムアウト30秒・サーキットブレーカーなしで呼び出していた。繁忙期にはリクエストが30秒のタイムアウトで宙ぶらりんになり、スレッドプールが埋まり尽くし、WMSのステータスコールバックはスレッドをまったく取得できず——40分間キューに滞留した。根本原因は実はタイムアウトではない。タイムアウトしたリクエストがスレッドを占有し続けたことだ。長いタイムアウトは短いものより下流を傷つける——多くのエンジニアが逆に思い込んでいる結論である。
数字:リトライ増幅は見た目より怖い
計算をもう一段進めよう。リトライ嵐の破壊力は、組み合わさる2つの乗数から来る:深さ——ホップが1つ増えるごとに増幅がリトライ回数分だけ掛け合わされる。期間——タイムアウトが長いほど、宙ぶらりんのリクエストがリソースを長く占有し、下流の回復ウィンドウは短くなる。AWS Architecture Blog の2015年の分析「Exponential Backoff And Jitter」によれば、固定リズムのリトライにはもう1つの殺し屋が隠れている:同期化だ。全クライアントが同じ瞬間にタイムアウトし、同じ瞬間にリトライし、波のように共振する——下流が一息つくやいなや、次の波が来る。
つまりあの夜の崩壊は「トラフィックが多すぎた」のではなく「リトライが同期しすぎた」ことだった。OMS・WMS・TMSはすべて同じテンプレート——タイムアウト5秒、即リトライ3回——で完璧に同期して打ち、まるで3つの群衆が同時に1つのドアに殺到するように。これが、多くのポストモーテムが「サーバ増強」と結論しながら改善が乏しい理由でもある:サーバは容量を増やすが、嵐が食うのは回復の時間ウィンドウだ。次元が違う。
帰属:4つのリトライメカニズム、そして「バックオフ+ジッター+ブレーカー」だけが生き残る理由
一般的なリトライ戦略を並べてみると、明確な物語が見える:
| 戦略 | メカニズム | 増幅 | 致命的欠点 |
|---|---|---|---|
| 即時リトライ | 即座に再送、最大N回 | N倍、障害の持続時間に応じて増大 | 下流の回復前に第2波が到着する |
| 固定間隔リトライ | T秒ごとに再送 | N倍、ばらつきは限定的 | 全クライアントが一斉にリトライ——共振 |
| 指数バックオフ | 待機が 2s → 4s → 8s と伸びる | 時間とともに減衰、回復の余裕を生む | リトライの同期化は直らない |
| バックオフ+ジッター | バックオフにランダムなジッターを追加 | 減衰し、非同期化する | 正しく実装するのが少し難しい |
| サーキットブレーカー+フォールバック | 失敗率の閾値で開放、ハーフオープンでプローブ | ほぼゼロ | 設計されたフォールバック経路が必要 |
バックオフの価値は「どんどん遅くなること」で、回復の時間を稼ぐ。ジッターの価値は同期化を壊すこと——リトライ嵐の真の燃料はリトライそのものではなく、全クライアントが同じ秒にリトライすることだ。サーキットブレーカーは Michael Nygard が Release It! で紹介したパターンで、失敗率の閾値を超えると回路を開放してリクエスト送信を止め、ハーフオープンのプローブを経てトラフィックを戻す。WMSとキャリアの連携ではほぼ必須である。スロットルされたキャリアAPIを叩き続ければ、ブロックリスト入りするだけだ。
もう1つ、過小評価されているルール:リトライに値するのは冪等なエンドポイントだけだ。注文確定や在庫引当のような書き込み操作を、冪等キーなしでリトライすれば、二重注文・二重引当になりうる——タイムアウトよりはるかに高くつく。多くのWMS/OMS連携ドキュメントは「3回リトライ」と何気なく書き、「注文が2回通ったらどうする?」には決して答えない。
実践:倉庫システム連携のための3つのルール
第1に、タイムアウトを階層化せよ。エッジのクエリは3秒、コアの注文APIは10秒、重いバッチ照合は同期HTTPを完全に捨てて非同期キューへ。長いタイムアウトは寛容なのではない——リソースを長く占有するだけだ。
第2に、リトライポリシーはコードのデフォルトではなく連携ドキュメントに書け。バックオフの基準、ジッターの範囲、最大試行回数、ブレーカーの閾値——連携テストで上流・下流と合わせるべき4つの数字だ。あの夜の崩壊は、3つの層が1つのテンプレート設定を共有し、共振を誰も考えなかったことが直接の原因だった。
第3に、下流をスロットルし、バルクヘッドで隔離せよ。TMSの運賃請求書照会とWMSのステータスコールバックはスレッドプールを共有すべきではない。一方が飽和しても他方を殺してはならない。外部キャリアAPIへのクライアント側スロットリングも重要だ——彼らのレートリミットは彼らを守り、あなたのものはあなたを守る。
強調すべき反直感的な判断がもう1つある:タイムアウト後に「長く待ってからリトライする」は、「速く失敗して呼び出し元にキューイングさせる」よりしばしば悪い。スレッドプールは同時占有で死ぬのであり、リトライ回数で死ぬのではない。1つのリクエストが30秒間スレッドを占有することは、3秒のタイムアウト+2回のリトライより下流を傷つける。短いタイムアウト、少ないリトライ、呼び出し元に表面化させた速い失敗によるキューイング——見た目はUXが悪そうだが、チェーン全体にとって最も責任ある選択だ。
潮流は明確だ:リトライは「呼び出し元の責任」から「インフラの能力」へ移行している。デッドレターキュー、Outboxパターン、サービスメッシュがリトライポリシーをインフラ層に押し込み、ビジネスロジックは手書きのリトライを書かなくなっている。それは進歩だ——嵐の根本原因の1つは、各チームが独自のリトライを書き、リズムが決して揃わなかったことだ。ビジネスロジックからリトライが完全に消える日、嵐は真に飼い慣らされる。それまでは、WMS連携ドキュメントの「リトライ戦略」の章は書き直すに値する——今すぐに。
Dr. Chen(サプライチェーン研究者)著
英語版からの翻訳。内容に相違がある場合は英語版を優先します。










