指数バックオフ
リトライ間隔を指数関数的に増加させ、障害時のシステム負荷を軽減するリトライ戦略
耐障害性設計
指数バックオフとは
指数バックオフ (Exponential Backoff) は、リトライ間隔を指数関数的に増加させ、障害時のシステム負荷を軽減するリトライ戦略である。AWS SDK はデフォルトで指数バックオフを実装している。
リトライ間隔
リトライ 1: 1 秒後
リトライ 2: 2 秒後
リトライ 3: 4 秒後
リトライ 4: 8 秒後
リトライ 5: 16 秒後 (最大リトライ回数に達したら失敗)
計算式: delay = min(base * 2^attempt, maxDelay)
ジッター (Jitter)
❌ ジッターなし:
100 クライアントが同時にリトライ → 再び過負荷
✅ ジッターあり:
各クライアントがランダムな遅延を追加 → 負荷が分散
Full Jitter: delay = random(0, base * 2^attempt)
Equal Jitter: delay = base * 2^attempt / 2 + random(0, base * 2^attempt / 2)
TypeScript での実装
async function withRetry<T>(
fn: () => Promise<T>,
maxAttempts = 3,
baseDelay = 1000,
): Promise<T> {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fn();
} catch (e) {
if (attempt === maxAttempts - 1) throw e;
const delay = Math.min(baseDelay * 2 ** attempt, 30000);
const jitter = Math.random() * delay; // Full Jitter
await new Promise(r => setTimeout(r, jitter));
}
}
throw new Error('Unreachable');
}
AWS SDK のリトライ
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({
maxAttempts: 5, // デフォルト: 3
// SDK が自動的に指数バックオフ + ジッターでリトライ
});
リトライすべきエラー
| ステータス | リトライ | 理由 |
|---|---|---|
| 429 | ✅ | レート制限 (一時的) |
| 500 | ✅ | サーバーエラー (一時的) |
| 503 | ✅ | サービス利用不可 (一時的) |
| 400 | ❌ | クライアントエラー (修正が必要) |
| 404 | ❌ | リソースが存在しない |
Step Functions のリトライ
ProcessPayment:
Type: Task
Resource: !GetAtt PaymentFunction.Arn
Retry:
- ErrorEquals: [ServiceException, TooManyRequestsException]
IntervalSeconds: 2
MaxAttempts: 3
BackoffRate: 2 # 2秒 → 4秒 → 8秒
Catch:
- ErrorEquals: [States.ALL]
Next: HandleFailure
指数バックオフの注意点
| 注意点 | 対策 |
|---|---|
| 最大遅延の上限 | 30 秒程度にキャップ |
| 最大リトライ回数 | 3〜5 回で打ち切り |
| 冪等性の確保 | リトライで副作用が重複しないように |
| タイムアウトとの整合 | Lambda のタイムアウト内に収める |
理論と実装の両面から学ぶなら関連書籍が参考になる。