mazyu36の日記

某SIer所属のクラウドエンジニアのブログ

Step Functionsでエクスポネンシャルバックオフやジッターの設定が便利になった

個人的に待ち望んでいた、Step Functionsにおけるエクスポネンシャルバックオフの上限設定や、ジッターの設定が追加されたので試してみました。

2023/9/7のアップデートにおける enhanced error handling で追加されています。

aws.amazon.com

目次

1.そもそもエクスポネンシャルバックオフやジッターとは

以下のBuilder's Libraryの記事が参考になります。

aws.amazon.com

分散システムにおける処理失敗時などのリトライにおいて、以下の2つのプラクティスがよくセットで語られます。

  • エクスポネンシャル・バックオフ:リトライ時にすぐリトライを行うのではなく、リトライごとに間隔を空けていく(1秒→2秒→4秒→・・・など)。徐々に間隔を開けることでリトライの回数を抑えることが目的。
  • ジッター:リトライのタイミングにランダム性(ゆらぎ)を持たせる。全リクエストが同時にリトライを行うと受信側に負荷がかかるので、ランダム性を持たせることでタイミングを分散させることができる。

Step Functionsのネイティブの機能としての対応状況は以下でした。

  • エクスポネンシャル・バックオフ:対応はしていたが上限は設定できない。間隔が空きすぎないよう、上限を設けることが一般的だがStep Functionsでは設定できなかった(1秒→2秒→4秒→10秒→10秒→...のように10秒より間隔は増やさないようにする等ができない)
  • ジッター:設定自体できない。

上記のできない部分について作り込みが必要でしたが、今回のStep Functionsアップデートでネイティブの機能として対応しました。

2. Step Functionsのアップデート内容の確認

以下のようなRDSクラスターを起動するだけのステートマシンで確認してみます。

まず執筆時点(2023/9/7)でジッター未対応の大阪リージョンでリトライの設定項目を確認してみます。

State(ここではStartDBCluster)を選択し、「エラー処理」タブでリトライの設定を確認します。

エクスポネンシャルバックオフのレート設定のためのBackoff rateありますが、ジッターに関する項目は見当たりません。

続いて同様に東京リージョンで確認してみます。

大阪リージョンでは存在しなかった 最大遅延ジッターを追加 が追加されています。

これらの項目の意味をドキュメントで確認します。

docs.aws.amazon.com

最大遅延

ドキュメントの記載は以下です。

MaxDelaySeconds (Optional) A positive integer that sets the maximum value, in seconds, up to which a retry interval can increase. This field is helpful to use with the BackoffRate field. The value you specify in this field limits the exponential wait times resulting > from the backoff rate multiplier applied to each consecutive retry attempt. You must specify a value greater than 0 > and less than 31622401 for MaxDelaySeconds.

If you don't specify this value, Step Functions doesn't limit the wait times between retry attempts.

要するにエクスポネンシャル・バックオフにおけるリトライ間隔の最大値の設定になります。

ジッターを追加

ドキュメントの記載は以下です。

JitterStrategy (Optional) A string that determines whether or not to include jitter in the wait times between consecutive retry attempts. Jitter > reduces simultaneous retry attempts by spreading these out over a randomized delay interval. This string accepts FULL or NONE as its values. The default value is NONE.

要はジッターをON/OFFにするフラグです。

また具体例も記載されています。

For example, say you have set MaxAttempts as 3, IntervalSeconds as 2, and BackoffRate as 2. The first retry attempt takes place two seconds after the error occurs. The second retry takes place four seconds after the first retry attempt and the third retry takes place eight seconds after the second retry attempt. If you set JitterStrategy as > FULL, the first retry interval is randomized between 0 and 2 seconds, the second retry interval is randomized between 0 and 4 seconds, and the third retry interval is randomized between 0 and 8 seconds.

MaxAttemptsを3回、IntervalSecondsを2秒、BackoffRateを2倍としジッターをONにしたとします。

  • 1回目の再試行:IntervalSecondsが2秒なので、最初の処理失敗から0秒後〜2秒後のリトライが行われる。
  • 2回目の再試行:IntervalSeconds * BackoffRate が「間隔」となり、1回目の再試行失敗0秒後〜4秒後のどこかでリトライが行われる。
  • 3回目の再試行:IntervalSeconds * BackoffRate * BackoffRate が「間隔」となり、2回目の再試行失敗0秒後〜8秒後のどこかでリトライが行われる。

3. 動作確認

実際にStep Functionsを使用して動作確認します。

ステートマシンの実行を失敗の上リトライさせたいため、StartDBClusterのみのステートマシンを使用し、API実行時のクラスター識別子は存在しないものを指定します。

最大遅延の確認

まずは 最大遅延 の動作確認をします。以下のとおり設定します。

  • Interval:2秒
  • Max Attempts(リトライ回数):10回
  • Backoff rate:2倍
  • 最大遅延:10秒
  • ジッターを追加:チェックなし

リトライごとに間隔が2秒→4秒→8秒→10秒→10秒→.... となる想定です。

では実行してみます。

想定通りリトライされていそうです。

ここでは簡易的に TaskFailed~TaskScheduledの間隔をリトライ間隔として集計します。

リトライ回数 リトライ間隔
1回目 0時間 0分 2秒 71ミリ秒
2回目 0時間 0分 4秒 93ミリ秒
3回目 0時間 0分 8秒 65ミリ秒
4回目 0時間 0分 10秒 88ミリ秒
5回目 0時間 0分 10秒 87ミリ秒
6回目 0時間 0分 10秒 75ミリ秒
7回目 0時間 0分 10秒 72ミリ秒
8回目 0時間 0分 10秒 74ミリ秒
9回目 0時間 0分 10秒 83ミリ秒
10回目 0時間 0分 10秒 96ミリ秒

結果としては想定通りでした。4回目以降は 最大遅延の10秒から増えなくなっています。

ジッターの確認

次はジッターの確認を行います。設定内容としては以下です。

  • Interval:5秒
  • Max Attempts(リトライ回数):10回
  • Backoff rate:1倍
  • 最大遅延:5秒
  • ジッターを追加:チェックあり

エクスポネンシャル・バックオフは設けずに、リトライ間隔は5秒で固定としつつもジッターを設定しています。

では先ほどと同様に実行した結果を表で示します。

リトライ回数 リトライ間隔
1回目 0時間 0分 3秒 79ミリ秒
2回目 0時間 0分 2秒 183ミリ秒
3回目 0時間 0分 0秒 31ミリ秒
4回目 0時間 0分 0秒 29ミリ秒
5回目 0時間 0分 5秒 83ミリ秒
6回目 0時間 0分 1秒 77ミリ秒
7回目 0時間 0分 5秒 79ミリ秒
8回目 0時間 0分 3秒 73ミリ秒
9回目 0時間 0分 2秒 79ミリ秒
10回目 0時間 0分 3秒 87ミリ秒

想定通り0秒~5秒の中でランダムになっていました。

エクスポネンシャルバックオフ&ジッターの確認

最後にエクスポネンシャルバックオフとジッターを組み合わせてみます。

  • Interval:3秒
  • Max Attempts(リトライ回数):10回
  • Backoff rate:2倍
  • 最大遅延:15秒
  • ジッターを追加:チェックあり

リトライ間隔は 3秒→6秒→12秒→15秒→15秒→...となり、さらにジッターによりランダム性がある形となります。

実行してみたところ以下でした。

リトライ回数 リトライ間隔
1回目 0時間 0分 3秒 96ミリ秒
2回目 0時間 0分 0秒 32ミリ秒
3回目 0時間 0分 4秒 100ミリ秒
4回目 0時間 0分 4秒 88ミリ秒
5回目 0時間 0分 15秒 89ミリ秒
6回目 0時間 0分 15秒 73ミリ秒
7回目 0時間 0分 15秒 110ミリ秒
8回目 0時間 0分 15秒 79ミリ秒
9回目 0時間 0分 15秒 91ミリ秒
10回目 0時間 0分 15秒 83ミリ秒

4回目まではなんとなく良さそうなのですが、5回目以降は 最大遅延 の15秒で固定されているように見えます。

なんか設定をミスっているのか、仕様なのか、バグなのか、、、もう少し探究してみます。

AWS CDKの対応状況

CDK v2.95.0で上記に対応済みです。L2 Constructの場合addRetryで設定ができます。

以下のドキュメントが参考になります。

docs.aws.amazon.com

終わりに

今までStep Functionsのジッターは作り込んでいることが多かったので個人的には嬉しいアップデートです。

今後は活用していきたいと思います。