AWS CLI, AWS SDKのリトライ処理の実装について

AWS CLI, AWS SDKのリトライ処理の実装について

AWS CLI, AWS SDKのリトライ処理について、API実行時は、エクスポネンシャルバックオフのアルゴリズムによるリトライ処理を実行しますが、その具体的な内容について追ってみました。

リトライ処理は、リトライの基準、エクスポネンシャルバックオフの挙動等、CLIやSDKの言語、サービスによって異なることがあります。

AWS CLI or Python SDK

!!! 以下の記載内容は現在では古い記載もあります。今現在は、試行回数などの設定ができるようなっています。詳細は、下記ドキュメントをご参照ください。 !!!

デフォルトのリトライ設定について

https://github.com/boto/botocore/blob/1.16.1/botocore/data/_retry.json#L91-L113 ランダムな振れ幅を持ったエクスポネンシャルバックオフアルゴリズムで、5回のリトライ処理。

  "retry": {
    "__default__": {
      "max_attempts": 5,
      "delay": {
        "type": "exponential",
        "base": "rand",
        "growth_factor": 2
      },
      "policies": {
          "general_socket_errors": {"$ref": "general_socket_errors"},
          "general_server_error": {"$ref": "general_server_error"},
          "bad_gateway": {"$ref": "bad_gateway"},
          "service_unavailable": {"$ref": "service_unavailable"},
          "gateway_timeout": {"$ref": "gateway_timeout"},
          "limit_exceeded": {"$ref": "limit_exceeded"},
          "throttling_exception": {"$ref": "throttling_exception"},
          "throttled_exception": {"$ref": "throttled_exception"},
          "request_throttled_exception": {"$ref": "request_throttled_exception"},
          "throttling": {"$ref": "throttling"},
          "too_many_requests": {"$ref": "too_many_requests"},
          "throughput_exceeded": {"$ref": "throughput_exceeded"}
      }
    },

retryの挙動を変更するには、jsonを変更するか以下のように気合い。

https://github.com/boto/botocore/issues/882

どのように呼び出しているか確認。

https://github.com/boto/botocore/blob/develop/botocore/client.py create_clientから_load_service_modelを呼び出す

_load_service_modelから_register_retriesを呼び出す

_register_retriesからload_dataを呼び出す

https://github.com/boto/botocore/blob/develop/botocore/loaders.py

ここでjsonのデータを登録する。

リトライのの挙動は、create_retry_handler()関数で返している。 https://github.com/boto/botocore/blob/develop/botocore/retryhandler.py#L72-L77

https://github.com/boto/botocore/blob/develop/botocore/retryhandler.py#L39-L58

デフォルトでは、rand を base としているため、base = random.random() で取得した base の値から、リトライの時間間隔を base * (growth_factor ** (attempts - 1)) で計算する。

Java SDK

Java SDK デフォルトのClientConfigurationオブジェクトの内容について

デフォルトのリトライポリシーは、PredefinedRetryPolicies.DEFAULTで指定されている内容になる。  そのため、設定内容は以下のとおりとなる。

  • リトライ回数は3回

  • リトライする条件はDEFAULT_RETRY_CONDITIONにて指定され、HTTP StatusCodeが500/503、スロットリングによる400エラー、Clock skewエラー時、IOエラー時。

  • リトライの待ち時間は、DEFAULT_BACKOFF_STRATEGYにて指定され、Exponential Backoff(BASE_DELAY 100ms、MAX_BACKOFF_IN_MILLISECONDS 20秒)となる

  • タイムアウトは、ClientConfigurationのDEFAULT_CONNECTION_TIMEOUT(10秒)、DEFAULT_SOCKET_TIMEOUT(50秒)となる

以下の箇所について、 DEFAULT_RETRY_CONDITIONには、リトライの判定条件に関するオブジェクトが格納されており、 DEFAULT_BACKOFF_STRATEGYには、リトライをどのように行うかを判定するクラスのオブジェクトが格納されている。

上記の設定を元に、getDefaultRetryPolicy()関数によって RetryPolicy クラスのオブジェクトを返す関数を定義する。

getDefaultRetryPolicy()関数は以下の箇所で呼び出されて、DEFAULT 変数に格納されている。ここで格納された RetryPolicy クラスの DEFAULT 変数は別のクラス等から参照され、リトライ処理の挙動を決定する。

ClientConfiguration クラスについて

ClientConfiguration クラスにつきましては、リトライ処理等のデフォルト設定を上書きして、クライアントサイドで値等をカスタマイズしていただけるクラスとなっている。

https://github.com/aws/aws-sdk-java/blob/master/aws-java-sdk-core/src/main/java/com/amazonaws/ClientConfiguration.java

以下で各種初期値の設定をしている。

以下の箇所で、先ほどの PredefinedRetryPolicies クラスの DEFAULT の値が代入され、retryPolicy の変数として格納されている。

クライアント側で、ClientConfiguration クラスの設定をいただいた場合、以下の箇所で設定が上書きされる。

以上から、ClientConfiguration クラスを設定していない場合におきましてもリトライ処理は実行される。

なお、リトライ処理の判定に関しては、PredefinedRetryPolicies クラスと同一ファイル上にある SDKDefaultRetryCondition クラスの shouldRetry() 関数で判定が行われている。

こちらでリトライ処理の判定が行われているが、自分でもリトライ処理を実装していただくことでより確実にリトライ処理を行うことが可能となっている。

以下で、デフォルトでどのようなアルゴリズムでリトライ処理が実装されるかが定義されている。 スロットリングしていないときは、Full Jitter Backoffで、スロットリングしているときは、Equal Jitter Backoffとなっている。

https://github.com/aws/aws-sdk-java/blob/master/aws-java-sdk-core/src/main/java/com/amazonaws/retry/PredefinedBackoffStrategies.java

JavaScript SDK

JavaScript SDKでは

  • リトライ回数3回(DynamoDBでは10回)

  • リトライ基準は、ステータスコードが、5XXエラー全般、もしくは429のときか、タイムアウト時。

JavaScript SDKのリトライ処理は、lib/直下のservice.jsで基本的に定義されている。

リトライ回数

https://github.com/aws/aws-sdk-js/blob/73d1c78f21793206e9db0b54161b64db9ab54ff2/lib/service.js

AWS.Serviceでデフォルトでは、defaultRetryCountとして3回と定義。

ただし、DynamoDB に関しては、デフォルトで10回と定義されている。

numRetries()関数で実際のリトライ回数を返すようになっている。

リトライ間隔

retryDelays()関数から、AWS.util.calculateRetryDelay()関数を呼び出している。

AWS.util.calculateRetryDelay()関数の処理内容について、設定内容から確認。

https://github.com/aws/aws-sdk-js/blob/9f1237b605f60d70753f5d1c7ac7bffe4d4430d5/lib/config.d.ts#L139-L150

ConfigurationOptionsクラスという抽象クラスで retryDelayOptions のプロパティを持つ

RetryDelayOptionsはbaseというエクスポネンシャルバックオフのベースの時間(ミリ秒単位, デフォルト 100ms)とバックオフアルゴリズムをカスタマイズする場合はそちらを定義したクラスを定義できるようになっている。

https://github.com/aws/aws-sdk-js/blob/2b6bcbdec1f274fe931640c1b61ece999aae7a19/lib/util.js#L833-L852

最大リトライ回数は、各サービスで定義しるものに準じる。デフォルト設定は0。 リトライの時間間隔は、calculateRetryDelay()関数で計算。

retryDelayOptionsのbaseで設定した値をベースに、リトライ回数の2のべき乗の積に0~1の間のランダムな小数の積をかけられた時間だけ待機。

リトライ基準

ステータスコードが5XXエラーか429エラーのとき。もしくはタイムアウトの時。

タイムアウトは、calculateRetryDelay()関数で計算したdelayの時間に、retry-after ヘッダーで定義された秒数を足したもの。

エクスポネンシャルバックオフアルゴリズムの待機時間の決定式について

  • 純粋なエクスポネンシャルバックオフアルゴリズム

  • Full Jitter

  • Equal Jitter

https://www.awsarchitectureblog.com/2015/03/backoff.html

Last updated