操作して学ぶ
指数バックオフとジッタ可視化
障害から復旧した瞬間、待たされていたクライアントが一斉にリトライします。 サーバーは捌ききれず取りこぼし、取りこぼされた側がまた同時に再送する——このリトライストームが回復を妨げます。 5つのリトライ方式を同じ条件・同じ乱数で並べて走らせ、群れがどう散るかを比べてください。
固定間隔(バックオフ無し)
delay = base
毎回同じ間隔で再送。群れが崩れず、同じ瞬間に何度も殺到する
指数バックオフ(ジッタ無し)
delay = min(cap, base × 2^attempt)
間隔は広がるが全員が同じだけ待つので、群れは同期したまま
Full Jitter
delay = random(0, min(cap, base × 2^attempt))
待ち時間を0〜上限の一様乱数に。群れが窓全体へ散る
Equal Jitter
delay = t/2 + random(0, t/2) (t = min(cap, base × 2^attempt))
半分は必ず待ち、残り半分を乱数に。最短待ち時間を確保しつつ散らす
Decorrelated Jitter総送信が最小
delay = min(cap, random(base, 前回の遅延 × 3))
前回の遅延を種にして伸ばす。散らしつつ上限に張り付きにくい
グラフは1ティックあたりの到着(リトライ)件数で、5方式とも同じ縦横スケールです。破線がサーバー容量で、 これを超えた分がその場で失敗して再びリトライに回ります。ティック0の巨大な山はどの方式でも同じ——全員が同時に復帰する以上、最初の殺到だけは避けられません。バックオフが制御できるのは、その後の山の形です。
なお、このモデルはサーバー容量を負荷によらず一定としています。実際には過負荷そのものが容量を削るため、 リトライを撃ち続ける方式の不利は、ここに出ている数字よりさらに大きくなります。
試してほしい3つの操作
- 既定の「復旧直後の殺到」のまま、上2つと下3つのグラフを見比べる。固定間隔と指数バックオフ(ジッタ無し)は、ティック0のあとも同じ高さの山が等間隔で立ち続けます。 間隔が伸びても全員が同じだけ待つので群れは崩れないのが、指数バックオフだけでは足りない理由です。
- 指数バックオフ(ジッタ無し)の「全員成功」欄を見る。この方式だけ時間内に終わりません。上限(cap)に張り付いた群れが同期したまま衝突し続け、毎ラウンド容量ぶんしか進まないためです。 ジッタを入れた3方式はいずれも完了し、総送信も大きく減ります。
- 容量スライダーを0にする。相手が完全に落ちている状況では結果が逆転し、Full Jitter が素の指数バックオフより多く送信します。 期待待ち時間が半分になるためで、ジッタは万能ではなく「捌ける相手の容量を無駄なく使う」ための道具だと分かります。
このモデルが扱っていないこと
サーバー容量は負荷によらず一定としています。実際には過負荷そのものが容量を削るため、撃ち続ける方式の不利は ここに出る数字より大きくなります。また、リトライ回数の上限・サーキットブレーカ・多層構成での乗算的な増幅・ そして総量を有界化する再試行予算(トークンバケット)は モデルに入れていません。タイミング制御はあくまで波の形を均す対症療法で、増幅率そのものを抑える本丸は再試行予算です。 その設計論は下の解説記事で扱っています。