テック技報最新号へ →
コード

リトライは「1 リクエストごとの回数」だけでなく全体の予算で制限する(full jitter と組み合わせる)

各呼び出しが最大 3 回リトライする設定だと、相手が落ちているときに送る量は通常の 4 倍になり、復旧を妨げる。リトライの量を全体で「通常のトラフィックの 1 割程度まで」と決めておき、待ち時間には full jitter を使う。

@amitsinha__07 · 投稿 2026-11-03
#infra#distributed-systems#retry#backoff#reliability

何が起きるか

相手のサービスが落ちかけているとき、全クライアントが一斉にリトライすると、ただでさえ処理しきれていない相手にリクエストが何倍も届く。待ち時間が固定や単純な指数バックオフだと、リトライが同じタイミングにそろって波になる。どちらも障害を長引かせる原因になる。

やり方

  1. リトライ予算: 直近の成功したリクエストの数に対して、リトライに使える数の上限(例: 10%)を決める。上限に達したらリトライせず、すぐ失敗を返す。
  2. full jitter: 待ち時間を「0 から上限までの一様乱数」にする。上限は指数的に増やし、最大値で頭打ちにする。
ts
// リトライ予算: 成功ごとに 0.1 枚ずつトークンがたまり、リトライ 1 回で 1 枚使う
class RetryBudget {
  private tokens = 10;
  constructor(private ratio = 0.1, private max = 10) {}
  onSuccess() { this.tokens = Math.min(this.max, this.tokens + this.ratio); }
  tryRetry(): boolean {
    if (this.tokens < 1) return false;
    this.tokens -= 1;
    return true;
  }
}

// full jitter: 0〜min(cap, base * 2^attempt) の乱数
const backoff = (attempt: number, base = 100, cap = 10_000) =>
  Math.random() * Math.min(cap, base * 2 ** attempt);
  • 予算はクライアント(またはプロセス)全体で 1 つ持つ。リクエストごとに持つと意味がない。
  • Envoy の retry_budget、gRPC の retryThrottling など、プロキシや RPC ライブラリが同じ仕組みを持っていることも多い。自前で書く前に使っているものの設定を確かめる。

注意点

  • リトライしてよいのは、二回届いても問題ない(冪等な)操作か、冪等キーを付けた操作だけ。
  • 複数の層(ブラウザ、API サーバー、その先の呼び出し)がそれぞれリトライすると回数が掛け算で増える。リトライはどこか 1 層に寄せる。
  • 1 割という数字は投稿者の目安。サービスの性質に合わせて決める。

出典

X の元の投稿を開く