LoginSignup
16
16

バックオフ戦略 (Backoff Strategy)について

Last updated at Posted at 2024-02-20

はじめに

とあるリトライ処理するとき徐々にリトライの間隔を伸ばしたほうが良さそうだな〜となんとなく実装していました。後々そのリトライ時に間隔を伸ばしてくことをバックオフ戦略と呼ぶと知ったので深堀りしてみます。

バックオフ戦略とは

リトライ間隔を徐々に増加させながらリトライする処理のこと。

例:0.5秒後、1秒後、2秒後、4秒後...にリトライ

メリット・デメリット

メリット
・トラフィックの軽減:
待機時間を設けることで、サーバーやネットワークへの負荷を減らせる。

・リトライ成功率上昇:
待機時間を徐々に増加させることで、システム障害から回復するまで時間を稼げる。

デメリット
・レスポンス時間の増加
システム全体のレスポンス時間が増加する可能性

・適切なリトライ時間調整
処理や負荷、様々な状況により適切なリトライ時間を設定する手間や難しさがある。

実装例

指数バックオフ Exponential Backoff

Swiftで指数バックオフを記述してみます。再帰的に呼び出すような記述にしました。
これでリトライの待機間隔が指数関数的に伸びていきます。

Swift
func exponentialBackoff(attempt: Int, maxAttempt: Int, delay: TimeInterval,
                        maxDelay: TimeInterval, multiplier: Double,
                        completion: @escaping () -> Void) {
                        
    guard attempt <= maxAttempt else {
        print("リトライ上限")
        return
    }
    
    let currentDelay = min(delay * pow(multiplier, Double(attempt)), maxDelay)
    print("\(attempt)回目、 待機 \(currentDelay) 秒")
    
    DispatchQueue.main.asyncAfter(deadline: .now() + currentDelay) {
        let result = API.call()
    
        // 成功したら終了
        if result = success {
        completion()
        } else {
        // 失敗したら再帰的に自身を呼ぶ
        exponentialBackoff(attempt: attempt + 1, maxAttempt: maxAttempt,
                           delay: delay, maxDelay: maxDelay,
                           multiplier: multiplier, completion: completion)
        }
    }
}

ジッター付きバックオフ

指数バックオフはリトライのタイミングが同時に大量に重なると以後のリトライ時も同時に行われるという欠点があります。

そこで一定の待機時間にランダムな時間を加えることで、再試行のパターンをよりランダム化し負荷を軽減するジッター(ゆらぎ)バックオフがあります。ランダム幅によっては遅延につながるので使い分けが必要そうです。Javaで見てみましょう。

Java
public class JitterBackoff {
    private static final Random random = new Random();

    // ジッターを含んだバックオフ時間を計算するメソッド
    public static long calculateBackoffTime(long baseBackoffTime) {
        // ランダムなジッターを生成する
        long jitter = random.nextInt(1000); // 0から999までのランダムな値を生成
        // ジッターを加えてバックオフ時間を計算する
        return baseBackoffTime + jitter;
    }

    public static void main(String[] args) {
        long baseBackoffTime = 5000; // 基本待機時間(ミリ秒)
        long backoffTimeWithJitter = calculateBackoffTime(baseBackoffTime);
        System.out.println("バックオフ時間(ジッター付き): " + backoffTimeWithJitter + "ミリ秒");
    }
}

指数バックオフとは異なり、待ち時間が等間隔で増加する線形バックオフや一定の間隔で再試行を行う定期的バックオフがありますが割愛します。

AWSの記事によると

結論、AWSはバックオフ推奨でした。

Amazonで使用する推奨ソリューションは、バックオフです。すぐに積極的な再試行する代わりに、クライアントは試行の間にある程度の時間を待ちます。最も一般的なパターンはエクスポネンシャルバックオフで、試行ごとに待機時間が急激に増加します。エクスポネンシャルバックオフは急速に成長するため、非常に長いバックオフ時間につながる可能性があります。

より詳細な指数バックオフとジッターの比較に関しての記事は紹介まで。

まとめ

バックオフ戦略のメリット、デメリットを考えて状況に合わせて使い分けることが大切だと学びました。
そもそも失敗しないようにする、クライアントから不必要にAPIを呼ばない等 他にできることも考慮して実装したいです。

最後に

私の働いている会社で経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談から応募してみてください!

16
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
16