1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Go言語】お手軽Exponential Backoff And Jitter

Last updated at Posted at 2023-05-04

「エクスポネンシャルバックオーーーーーーーフッ!!!」

技名ではなくリトライ時に使うアルゴリズムの話です。

Exponential Backoff And Jitter とは

Exponential Backoff

分散システムとかでネットワーク通信に失敗した時、成功するまでやり直す(リトライ)事ってあるよね。

でも通信に失敗した時ってネットワークや通信先サーバーの高負荷が原因だったりするから、
短時間に何度もリトライするとさらに負荷を増やしちゃうかもしれないんだ。

そんなときはExponential Backoff!
初回リトライまでの間隔は1秒、次は2秒、その次は4秒..8秒....みたいにリトライ間隔を指数関数的(Exponential)に後退(Backoff)させることでネットワークや接続先サーバーの過負荷を軽減さえられるんだ。

Jitter

Exponential Backoffだけだとちょっと不安、例えば同時に100クライアントからアクセスされている場合、
1秒、2秒、4秒、8秒....のタイミングでドカッと100アクセスされてしまう可能性がある。

そんなときはJitter!
クライアントAはリトライ間隔を0.92秒、1.97秒、4.01秒、8.09秒...
クライアントBはリトライ間隔を1.06秒、2.03秒、3.97秒、7.92秒...

みたいに多少の揺らぎ(Jitter)を導入することでリクエスト集中の問題を解決できるよ。

GO言語でExponential Backoff And Jitterをやってみる

本題に入る。
今回は簡単にExponential Backoff And Jitterができる「retry」パッケージを使うよ。

まずはコード

// リトライしたい処理を定義
op := func() (string, error) {
    fmt.Printf("some form of processing...(%v)\n", time.Now())
    return "", errors.New("Error!!")
}

// リトライしたい処理をRetry関数に渡す
result, err := retry.RetryOneResult(op)

↓出力↓

some form of processing...(2023-05-04 22:41:23.8943312 +0900 JST m=+0.003652001)
some form of processing...(2023-05-04 22:41:24.1863735 +0900 JST m=+0.295694301)
some form of processing...(2023-05-04 22:41:24.684814 +0900 JST m=+0.794134801)
some form of processing...(2023-05-04 22:41:25.5369253 +0900 JST m=+1.646246101)
some form of processing...(2023-05-04 22:41:27.5995704 +0900 JST m=+3.708891201)
Fail: Maximum number of retries reached

こんな感じで簡単にリトライができるよ。
Go Playgroundでも書いてみた。

デフォルトは最大5回のリトライで初回リトライまでが100ミリ秒、最大の遅延は10秒になるよ。
このあたりは引数で調整可能。

初回リトライを2秒、最大3回にしてみる

以下のように引数を増やしてあげると簡単に調整ができるよ。

// リトライしたい処理を定義
op := func() (string, error) {
    fmt.Printf("some form of processing...(%v)\n", time.Now())
    return "", errors.New("Error!!")
}

// リトライしたい処理をRetry関数に渡す(初回リトライを2秒、最大3回)
result, err := retry.RetryOneResult(op, retry.WithInitialDelay(2*time.Second), retry.WithMaxRetries(3))
if err != nil {
    fmt.Println("Fail:", err)
} else {
    fmt.Println("Succeed:", result)
}

↓出力↓

some form of processing...(2023-05-04 22:50:57.5021196 +0900 JST m=+0.003110101)
some form of processing...(2023-05-04 22:51:01.5844456 +0900 JST m=+4.085436101)
some form of processing...(2023-05-04 22:51:10.9645184 +0900 JST m=+13.465508901)
Fail: Maximum number of retries reached

Go Playgroundでも書いてみた。

おしまい

みんなもネットワークやサーバーに優しいリトライをしよう!!

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?