🎓 レベル:標準 | 重要度:A(必須)
📎 前提:配送保証(at-most-once・at-least-once・exactly-once) | 関連:分散トランザクションとSaga・分散コンピューティングの誤謬(8つの誤謬)
要点(BLUF)
- 冪等性(idempotency)=同じ操作を何回実行しても結果が1回ぶんと同じ性質。再送・再試行が避けられない分散では、これが信頼性の背骨。
- 安全な再試行の道具立て:冪等性キー(重複排除、配送保証(at-most-once・at-least-once・exactly-once))+指数バックオフ(待機を倍々に延ばす)+ジッタ(待機をばらつかせて再殺到を防ぐ)+サーキットブレーカ(連続失敗で一時遮断)。
- ジッタが無いと「サンダリングハード」:障害復旧の瞬間に全クライアントが一斉再試行して二次災害。フルジッタでピークを W 倍ぶん下げられる(シミュで実証)。
問題設定 ── 再試行は諸刃の剣
ネットワークは喪失する(分散コンピューティングの誤謬(8つの誤謬))ので、再試行は必須。だが冪等でない再試行は状態を壊し(二重課金)、無秩序な再試行は過負荷を増幅する(落ちかけたサーバに殺到してとどめを刺す)。「安全に・優しく」再試行する設計が要ります。
仕組み ── 4つの信頼性パターン
1. 冪等性キー(重複排除)
クライアントが安定したリクエストIDを付け、サーバは処理済みIDを記憶して2回目以降は副作用なしで前回結果を返す。これで at-least-once 配送でも効果は exactly-once(配送保証(at-most-once・at-least-once・exactly-once) で残高140→50を実証)。
2. 指数バックオフ
失敗のたびに待機時間を倍々に延ばす:
即時連打を避け、相手の回復時間を与える。ただし**上限(cap)**を設けて無限に延びないようにする。
3. ジッタ(最重要)
バックオフだけだと「全員が同じ k で同じ時刻に再試行」して再殺到する。フルジッタは待機を uniform(0, wait_k) にrandomizeして時間軸に散らす。
4. サーキットブレーカ
連続失敗が閾値を超えたら回路を開いて(open)一定時間リクエストを即座に失敗させ、相手を休ませる。試験的に半開(half-open)で様子見し、回復したら閉じる(closed)。
flowchart LR
C["closed(通常)"] -->|"連続失敗が閾値超え"| O["open(即失敗・相手を休ませる)"]
O -->|"クールダウン経過"| H["half-open(試験送信)"]
H -->|"成功"| C
H -->|"失敗"| O
具体例 ── ジッタでピークを下げる(実機)
ラボ 07-02_backoff_jitter.py。共有障害から復旧した瞬間、待機窓 W=8 秒のラウンドにいる1000クライアントが再試行:
== ジッタなし(全員 t=W に集中) ==
使用スロット数: 1
ピーク同時再試行数: 1000 (負荷率 100.0%)
== フルジッタ([0,W) に分散) ==
使用スロット数: 8
ピーク同時再試行数: 140 (負荷率 14.0%)
ピーク低減率: 7.1 倍 (ジッタなし 1000 -> フルジッタ 140)
ジッタなしだと全員が同じ瞬間(窓の末尾)に再試行しピーク1000=全員集中。フルジッタは待機窓 [0,8) に均し、ピークは**140(14%)**へ——約 **7倍(≒W倍)**の低減。これがサーバ復旧直後の再殺到(サンダリングハード)を防ぎます。
正しさの観点 ── 安全性と活性、そして相手への配慮
- 安全性(壊さない):冪等性キーが担保。再試行が何回来ても副作用は1回ぶん。
- 活性(いつか成功):再試行が担保。ただしバックオフ+上限で無限ループを防ぐ(リトライ予算・最大回数)。
- システム全体の活性(道連れにしない):ジッタ+サーキットブレーカが担保。自分の再試行が相手を殺さないことまで含めて信頼性。
なぜ分散だと難しいか(直観)
再試行は「自分の成功確率」だけ見ると常に正義だが、全員が同じ判断をすると集団で相手を潰す(合成の誤謬)。分散の信頼性は、個々の最適でなく群れとしての振る舞いを設計すること。ジッタもサーキットブレーカも「自分が引くことで全体が回る」という協調の発想です。
⚠️ よくある誤解・落とし穴
- 「リトライすれば信頼性が上がる」→ 冪等性なしのリトライは信頼性を下げる(二重実行)。
- 「指数バックオフがあればジッタは不要」→ ジッタ無しだと同期再殺到が残る(実機で1000集中)。ジッタが効果の本体。
- 「リトライは無限でよい」→ リトライ予算・最大回数・全体タイムアウトが無いと、障害時にリクエストが雪だるま式に滞留。
- 「サーキットブレーカは諦め」→ むしろ相手を回復させ全体の活性を守る。**速い失敗(fail fast)**が全体最適なことがある。
対応ラボ
distributed-systems-study/labs/07-02_backoff_jitter.py(フルジッタが再試行ピークを1000→140に約7倍低減することを確認済み)。重複排除の実証は 配送保証(at-most-once・at-least-once・exactly-once) のラボ。
関連
- 冪等性の出発点は 配送保証(at-most-once・at-least-once・exactly-once)
- Sagaの補償も冪等が必須 分散トランザクションとSaga
- 再試行が要る前提は 分散コンピューティングの誤謬(8つの誤謬)