AWS でのエラー再試行とエクスポネンシャルバックオフ - AWS 全般のリファレンス

AWS でのエラー再試行とエクスポネンシャルバックオフ

DNS サーバー、スイッチ、ロードバランサーなど、ネットワークの多数のコンポーネントが、特定のリクエストの存続期間中どこでもエラーを生成する可能性があります。ネットワーク環境でこれらのエラー応答を処理する通常の方法は、クライアントアプリケーションで再試行を実装することです。この技術は、アプリケーションの信頼性を向上させ、開発者の運用コストを削減します。

各 AWS SDK には、自動再試行ロジックが実装されています。AWS SDK for Java はリクエストを自動的に再試行し、ClientConfiguration クラスを使用して再試行設定を構成できます。たとえば、最小限のレイテンシーで再試行なしでリクエストを行うウェブページの再試行ロジックを無効にすることができます。再試行を無効にするには、ClientConfiguration クラスを使用し、0maxErrorRetry 値を指定します。

AWS SDKを使用していない場合は、サーバー (5xx) またはスロットリングエラーを受け取った元のリクエストを再試行する必要があります。ただし、クライアントエラー (4xx) は、再試行する前にリクエストを修正して問題を解決する必要があることを示します。

簡単な再試行に加えて、各 AWS SDK はエクスポネンシャルバックオフアルゴリズムを実装し、フロー制御を改善します。エクスポネンシャルバックオフの背後にある考え方は、連続したエラー応答の再試行間の待機時間を徐々に長く使用することです。最大遅延間隔と最大再試行回数を実装する必要があります。最大遅延間隔と最大再試行回数は、必ずしも固定値であるとは限らず、実行されるオペレーション、およびネットワークレイテンシーなどのその他のローカル要因に基づいて設定する必要があります。

ほとんどのエクスポネンシャルバックオフアルゴリズムは、連続した衝突を防ぐためにジッター (ランダム化された遅延) を使用します。このような衝突を回避しようとしていないため、この乱数を使用する必要はありません。ただし、同時クライアントを使用する場合、ジッターはリクエストをより速く成功させるのに役立ちます。詳細については、 エクスポネンシャルバックオフとジッターのブログ記事を参照してください。

次の擬似コードは、増分遅延を使用してステータスをポーリングする方法の 1 つを示しています。

Do some asynchronous operation. retries = 0 DO wait for (2^retries * 100) milliseconds status = Get the result of the asynchronous operation. IF status = SUCCESS retry = false ELSE IF status = NOT_READY retry = true ELSE IF status = THROTTLED retry = true ELSE Some other error occurred, so stop calling the API. retry = false END IF retries = retries + 1 WHILE (retry AND (retries < MAX_RETRIES))

次のコードは、Java でこの増分遅延を実装する方法を示しています。

public enum Results { SUCCESS, NOT_READY, THROTTLED, SERVER_ERROR } /* * Performs an asynchronous operation, then polls for the result of the * operation using an incremental delay. */ public static void doOperationAndWaitForResult() { // Do some asynchronous operation. long token = asyncOperation(); int retries = 0; boolean retry = false; do { long waitTime = Math.min(getWaitTimeExp(retries), MAX_WAIT_INTERVAL); System.out.print(waitTime + "\n"); try { // Wait for the result. Thread.sleep(waitTime); // Get the result of the asynchronous operation. Results result = getAsyncOperationResult(token); if (Results.SUCCESS == result) { retry = false; } else if (Results.NOT_READY == result) { retry = true; } else if (Results.THROTTLED == result) { retry = true; } else if (Results.SERVER_ERROR == result) { retry = true; } else { // Some other error occurred, so stop calling the API. retry = false; } } catch (IllegalArgumentException | InterruptedException e) { System.out.println("Error sleeping thread: " + e.getMessage()); } catch (IOException e) { System.out.println("Error retrieving result: " + e.getMessage()); } catch (Exception e) { System.out.println("Error: " + e.getMessage()); } } while (retry && (retries++ < MAX_RETRIES)); } /* * Returns the next wait interval, in milliseconds, using an exponential * backoff algorithm. */ public static long getWaitTimeExp(int retryCount) { if (0 == retryCount) { return 0; } long waitTime = ((long) Math.pow(2, retryCount) * 100L); return waitTime; }