再試行方法

このページでは、Cloud Storage へのリクエストが失敗した場合の指数バックオフなど、再試行方法について説明します。

概要

Cloud Console やほとんどのクライアント ライブラリなどの Cloud Storage ツールの多くは、自動的に再試行方法を使用するため、通常は独自の再試行方法を実装する必要はありません。独自の再試行方法を実装する場合、リクエストの再試行が安全かどうかは、次の 2 つの要素で決まります。

  1. リクエストからの受信レスポンス。
  2. リクエストのべき等性。

これらの要因と使用が推奨される再試行アルゴリズムの説明については、再試行戦略の実装をご覧ください。

Cloud Storage ツールごとの再試行方法

以下のタブをクリックすると、各 Cloud Storage ツールの再試行方法について推奨事項が表示されます。

Console

Cloud Console が Cloud Storage にリクエストを送信し、必要なバックオフを処理します。

gsutil

gsutil は、レスポンス セクションに表示されたエラーを再試行します。その際、追加のアクションは必要ありません。次のようなエラーに対しては、対処が必要となる場合があります。

  • 認証情報が無効であるか、十分な権限がない。

  • プロキシ構成の問題でネットワークに接続できない。

  • -m top-level フラグを使用するコマンドで失敗した個々のオペレーション。

再試行可能なエラーの場合、次のような再送時間算出法に従ってリクエストを再試行します。デフォルトでは、gsutil は約 10 分間(1+2+4+8+16+32+60... 秒)で 23 回再試行します。

  • リクエストが失敗した場合、[0..1] 秒間待機して再試行します。
  • さらにリクエストが失敗した場合、[0..2] 秒待機して再試行します。
  • さらにリクエストが失敗した場合、[0..4] 秒間待機して再試行します。
  • このようにして、最大 23 回の再試行を繰り返します。1 回の再試行時間の上限はデフォルトで 60 秒です。

再試行の回数と 1 回の再試行時間の上限を構成するには、.boto 構成ファイル"[Boto]" セクションにある num_retriesmax_retry_delay 構成変数を編集します。

クライアント ライブラリ

C++

デフォルトの再試行動作

デフォルトでは、次の HTTP エラーコードに対する再試行と、切断または正常に確立されなかったことを示すソケットエラーに対する再試行がサポートされます。

  • 408 Request Timeout
  • 429 Too Many Requests
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout

C++ ライブラリの指数バックオフと再試行のすべての設定を構成できます。ライブラリで実装されているアルゴリズムが要件に合わない場合は、カスタムコードを作成して独自の戦略を実装できます。

設定 デフォルト値
自動再試行 True
リクエストの再試行の最大時間 15 分
初期待機(バックオフ)時間 1 秒
反復処理ごとの待機時間乗数 2
最大待機時間 5 分

デフォルトでは、C++ ライブラリは再試行可能なエラーですべてのオペレーションを再試行します。また、べき等にすることなく、繰り返し成功したときに複数のリソースを削除または作成できます。べき等オペレーションのみを再試行するには、google::cloud::storage::StrictIdempotencyPolicy を使用します。

再試行のカスタマイズ

再試行動作をカスタマイズするには、google::cloud::storage::Client オブジェクトの初期化時に次の値を指定します。

  • google::cloud::storage::RetryPolicyOption: このライブラリは google::cloud::storage::LimitedErrorCountRetryPolicy クラスと google::cloud::storage::LimitedTimeRetryPolicy クラスを提供します。独自のクラスを指定できますが、その場合、google::cloud::RetryPolicy インターフェースを実装する必要があります。

  • google::cloud::storage::BackoffPolicyOption: このライブラリは google::cloud::storage::ExponentialBackoffPolicy クラスを提供します。独自のクラスを指定できますが、その場合、google::cloud::storage::BackoffPolicy インターフェースを実装する必要があります。

  • google::cloud::storage::IdempotencyPolicyOption: このライブラリは google::cloud::storage::StrictIdempotencyPolicy クラスと google::cloud::storage::AlwaysRetryIdempotencyPolicy クラスを提供します。独自のクラスを指定できますが、その場合、google::cloud::storage::IdempotencyPolicy インターフェースを実装する必要があります。

namespace gcs = ::google::cloud::storage;
// Create the client configuration:
auto options = google::cloud::Options{};
// Retries only idempotent operations.
options.set<gcs::IdempotencyPolicyOption>(
    gcs::StrictIdempotencyPolicy().clone());
// On error, it backs off for 1 second, then 3 seconds, then 9 seconds, etc.
// The backoff time never grows larger than 1 minute. The strategy introduces
// jitter around the backoff delay.
options.set<gcs::BackoffPolicyOption>(
    gcs::ExponentialBackoffPolicy(
        /*initial_delay=*/std::chrono::seconds(1),
        /*maximum_delay=*/std::chrono::minutes(1),
        /*scaling=*/3.0)
        .clone());
// Retries all operations for up to 5 minutes, including any backoff time.
options.set<gcs::RetryPolicyOption>(
    gcs::LimitedTimeRetryPolicy(std::chrono::minutes(5)).clone());
return gcs::Client(std::move(options));

C#

C# クライアント ライブラリは、デフォルトで指数バックオフを使用します。

Go

Go クライアント ライブラリは、デフォルトで指数バックオフが使用されます。

Java

Java クライアント ライブラリは、デフォルトで指数バックオフを使用します。

Node.js

デフォルトの再試行動作

オペレーションでは、デフォルトで次のエラーコードの再試行がサポートされています。

  • 接続エラー:
    • EAI_again: これは DNS ルックアップ エラーです。詳細については、こちらをご覧ください。
    • Connection reset by peer: GCP が接続をリセットしたことを意味します。
    • Unexpected connection closure: GCP が接続を閉じていることを意味します。
  • HTTP コード:
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout

Node.js ライブラリでは、すべての指数バックオフ設定が構成可能です。デフォルトで、Node.js を使用したオペレーションでは、指数バックオフに次の設定を使用します。

設定 デフォルト値(秒)
自動再試行 True
再試行の最大回数 3
初期待機時間 1 秒
反復処理ごとの待機時間乗数 2
最大待機時間 64 秒
デフォルトの期限 600 秒

条件付きべき等である(条件付きで安全に再試行できる)Node.js オペレーションのサブセットがあります。これらのオペレーションは、特定の引数が含まれている場合にのみ再試行され、次の前提条件があります。

  • ifGenerationMatch または generation

    • メソッドに ifGenerationMatch または generation がオプションとして渡された場合は、安全に再試行できます。多くの場合、メソッドは一方のパラメータのみ受け入れます。
  • ifMetagenerationMatch

    • ifMetagenerationMatch がオプションとして渡された場合は、安全に再試行できます。

retryOptions.idempotencyStrategy はデフォルトで IdempotencyStrategy.RetryConditional に設定されています。デフォルトの再試行動作を変更する方法の例については、以下の再試行のカスタマイズのセクションをご覧ください。

再試行のカスタマイズ

Cloud Storage を初期化すると、retryOptions 構成ファイルも初期化されます。オーバーライドされない限り、構成におけるオプションは上の表の値に設定されます。デフォルトの再試行動作を変更するには、初期化時にカスタム再試行構成 retryOptions をストレージ コンストラクタに渡します。Node.js クライアント ライブラリでは、autoRetry パラメータを使用して、バックオフ方法に沿ったリクエストの再試行を自動的に行えます。

再試行動作をカスタマイズする方法については、次のコードサンプルをご覧ください。

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// The ID of your GCS bucket
// const bucketName = 'your-unique-bucket-name';

// The ID of your GCS file
// const fileName = 'your-file-name';

// Imports the Google Cloud client library
const {Storage} = require('@google-cloud/storage');

// Creates a client
const storage = new Storage({
  retryOptions: {
    // If this is false, requests will not retry and the parameters
    // below will not affect retry behavior.
    autoRetry: true,
    // The multiplier by which to increase the delay time between the
    // completion of failed requests, and the initiation of the subsequent
    // retrying request.
    retryDelayMultiplier: 3,
    // The total time between an initial request getting sent and its timeout.
    // After timeout, an error will be returned regardless of any retry attempts
    // made during this time period.
    totalTimeout: 500,
    // The maximum delay time between requests. When this value is reached,
    // retryDelayMultiplier will no longer be used to increase delay time.
    maxRetryDelay: 60,
    // The maximum number of automatic retries attempted before returning
    // the error.
    maxRetries: 5,
    // Will respect other retry settings and attempt to always retry
    // conditionally idempotent operations, regardless of precondition
    idempotencyStrategy: IdempotencyStrategy.RetryAlways,
  },
});
console.log(
  'Functions are customized to be retried according to the following parameters:'
);
console.log(`Auto Retry: ${storage.retryOptions.autoRetry}`);
console.log(
  `Retry delay multiplier: ${storage.retryOptions.retryDelayMultiplier}`
);
console.log(`Total timeout: ${storage.retryOptions.totalTimeout}`);
console.log(`Maximum retry delay: ${storage.retryOptions.maxRetryDelay}`);
console.log(`Maximum retries: ${storage.retryOptions.maxRetries}`);
console.log(
  `Idempotency strategy: ${storage.retryOptions.idempotencyStrategy}`
);

async function deleteFileWithCustomizedRetrySetting() {
  await storage.bucket(bucketName).file(fileName).delete();
  console.log(`File ${fileName} deleted with a customized retry strategy.`);
}

deleteFileWithCustomizedRetrySetting();

PHP

PHP クライアント ライブラリは、デフォルトで指数バックオフを使用します。

Python

デフォルトの再試行動作

オペレーションでは、デフォルトで次のエラーコードの再試行がサポートされています。

  • 接続エラー:
    • requests.exceptions.ConnectionError
    • requests.exceptions.ChunkedEncodingError(アップロードやダウンロードなどペイロード データをフェッチまたは送信するオペレーションのみ)
    • ConnectionError
  • HTTP コード:
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout

Python によるオペレーションでは、指数バックオフとして次のデフォルト設定が使用されます。

設定 デフォルト値(秒)
初期待機時間 1
反復処理ごとの待機時間乗数 2
最大待機時間 60
デフォルトの期限 120

特定の引数が含まれている場合、条件付きべき等(条件付きで安全に再試行できる)である Python オペレーションのサブセットがあります。これらのオペレーションは、条件のケースに一致した場合にのみ再試行されます。

  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED

    • メソッドに generation または if_generation_match が引数として渡された場合は、安全に再試行できます。多くの場合、メソッドはいずれかのパラメータを受け入れます。
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED

    • メソッドに if_metageneration_match が引数として渡された場合は、安全に再試行できます。
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

    • メソッドが etag を JSON リクエスト本文に挿入する場合は、安全に再試行できます。HMACKeyMetadata.update() の場合は、HMACKeyMetadata オブジェクト自体に etag を設定する必要があります。他のクラスの set_iam_policy() メソッドの場合は、メソッドに渡される「policy」引数に etag を設定する必要があります。

再試行のカスタマイズ

デフォルトの再試行動作を変更するには、with_XXX メソッドを呼び出して google.cloud.storage.retry.DEFAULT_RETRY オブジェクトのコピーを作成します。DEFAULT_RETRY パラメータを含めると、Python クライアント ライブラリは自動的にバックオフ戦略を使用してリクエストを再試行します。

with_predicate は、ペイロード データの取得やオブジェクトに送信するオペレーション(アップロードやダウンロードなど)ではサポートされていません。属性は、1 つずつ変更することをおすすめします。詳細については、google-api-core Retry リファレンスをご覧ください。

独自の条件付き再試行を構成するには、ConditionalRetryPolicy オブジェクトを作成し、カスタム Retry オブジェクトを DEFAULT_RETRY_IF_GENERATION_SPECIFIEDDEFAULT_RETRY_IF_METAGENERATION_SPECIFIED、または DEFAULT_RETRY_IF_ETAG_IN_JSON でラップします。

再試行動作をカスタマイズする方法については、次のコードサンプルをご覧ください。

from google.cloud import storage
from google.cloud.storage.retry import DEFAULT_RETRY

def configure_retries(bucket_name, blob_name):
    """Configures retries with customizations."""
    # The ID of your GCS bucket
    # bucket_name = "your-bucket-name"
    # The ID of your GCS object
    # blob_name = "your-object-name"

    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.blob(blob_name)

    # Customize retry with a deadline of 500 seconds (default=120 seconds).
    modified_retry = DEFAULT_RETRY.with_deadline(500.0)
    # Customize retry with an initial wait time of 1.5 (default=1.0).
    # Customize retry with a wait time multiplier per iteration of 1.2 (default=2.0).
    # Customize retry with a maximum wait time of 45.0 (default=60.0).
    modified_retry = modified_retry.with_delay(initial=1.5, multiplier=1.2, maximum=45.0)

    # blob.delete() uses DEFAULT_RETRY_IF_GENERATION_SPECIFIED by default.
    # Override with modified_retry so the function retries even if the generation
    # number is not specified.
    print(
        f"The following library method is customized to be retried according to the following configurations: {modified_retry}"
    )

    blob.delete(retry=modified_retry)
    print("Blob {} deleted with a customized retry strategy.".format(blob_name))

Ruby

Ruby クライアント ライブラリは、デフォルトで指数バックオフを使用します。

REST API

JSON または XML API を直接呼び出す場合は、指数バックオフ アルゴリズムを使用して独自の再試行方法を実装する必要があります。

再試行方法の実装

このセクションでは、独自の再試行方法を構築するときに考慮すべき要素と、使用が推奨される再試行アルゴリズムについて説明します。

イベントに

リクエストから返されたレスポンスは、リクエストの再試行に役立つかどうかを示します。通常、一時的な問題に関連するレスポンスは再試行できます。一方、永続的なエラーに関連するレスポンスは、リクエストを再試行する前に、承認や構成の変更などを行う必要があることを示します。次のレスポンスは、再試行する価値がある一時的な問題を示しています。

  • 4084295xx の HTTP レスポンス コード。
  • ソケット タイムアウトと TCP 切断。

詳細については、JSONXML のステータス コードとエラーコードをご覧ください。

べき等性

べき等であるリクエストは、繰り返し実行される可能性があり、ターゲットとするリソースを常に同じ終了状態のままにすることを意味します。たとえば、一覧表示のリクエストは、リソースを変更しないので、常にべき等です。一方、新しい Pub/Sub 通知の作成はべき等ではありません。リクエストが成功するたびに新しい通知 ID が生成されるためです。

たとえば、次のような条件を満たしていれば、べき等性を実現できます。

  • オペレーションを連続してリクエストしても、対象リソースに対して結果が生成される。

  • オペレーションが 1 回だけ成功する。

  • 対象リソースの状態に対して観察可能な結果がない。

再試行可能なレスポンスを受け取った場合は、リクエストのべき等性を考慮する必要があります。これは、べき等でないリクエストを再試行すると、競合状態などの競合が発生する可能性があるためです。

条件付きべき等性

リクエストのサブセットは条件付きべき等性になります。つまり、特定のオプション引数が含まれる場合にのみ、べき等になります。条件付きで安全に再試行できるオペレーションは、条件のケースに該当した場合にのみデフォルトで再試行されます。Cloud Storage は、リクエストの条件ケースとして前提条件と ETag を受け入れます。

オペレーションのべき等性

次の表に、べき等性の各カテゴリに属する Cloud Storage オペレーションの一覧を示します。

べき等性 オペレーション
常にべき等
  • すべての取得リクエストと一覧表示リクエスト
  • バケットを挿入または削除する
  • バケットの IAM ポリシーと権限のテスト
  • 保持ポリシーをロックする
  • HMAC キーまたは Pub/Sub 通知を削除する
条件付きべき等性
  • HTTP 前提条件として IfMetagenerationMatch または ETag を持つバケットの更新 / パッチ リクエスト
  • HTTP 前提条件として IfMetagenerationMatch または ETag を持つオブジェクトの更新 / パッチ リクエスト
  • HTTP 前提条件またはリソース本文で ETag を使用してバケットの IAM ポリシーを設定する
  • HTTP 前提条件またはリソースの本文で ETag を使用して HMAC キーを更新する
  • ifGenerationMatch を使用してオブジェクトを挿入、コピー、作成、書き換える
  • ifGenerationMatch(またはオブジェクト バージョンの世代番号)を持つオブジェクトを削除する
べき等でない
  • HMAC キーを作成する
  • Pub/Sub 通知を作成する
  • バケットとオブジェクトの ACL、またはデフォルト オブジェクト ACL のパッチ / 更新リクエストを作成、削除、または送信する

指数バックオフ アルゴリズム

レスポンスとべき等性の両方の条件を満たすリクエストについては、通常、切り捨て型指数バックオフを使用する必要があります。

切り捨て型指数バックオフは、ネットワーク アプリケーションの標準的なエラー処理方法で、クライアントはリクエスト間の遅延を増加させながら、失敗したリクエストを定期的に再試行します。

指数バックオフのアルゴリズムは、再試行の待ち時間の間隔を最大バックオフ時間まで増加させながら、指数関数的にリクエストを再試行します。次に例を示します。

  1. Cloud Storage へのリクエストを作成します。

  2. リクエストが失敗した場合、1 + random_number_milliseconds 秒待ってから、リクエストを再試行します。

  3. リクエストが失敗した場合、2 + random_number_milliseconds 秒待ってから、リクエストを再試行します。

  4. リクエストが失敗した場合、4 + random_number_milliseconds 秒待ってから、リクエストを再試行します。

  5. このようにして、最大 maximum_backoff 時間まで繰り返します。

  6. 最大時間(deadline)まで待機と再試行を継続しますが、再試行間の maximum_backoff の待機期間は増えません。

ここで

  • 待ち時間は min((2n +random_number_milliseconds),maximum_backoff) で、n はイテレーション(リクエスト)のたびに +1 されます。

  • 上記のフローで、random_number_milliseconds は、1,000 ミリ秒以下の乱数です。これにより、多数のクライアントが同期され、再試行が一度に実行されて、リクエストが同時に次々と送信されるような状況を避けることができます。random_number_milliseconds の値は再試行リクエストの後に毎回再計算されます。

  • 通常、maximum_backoff は 32 秒または 64 秒です。適切な値はユースケースによって異なります。

maximum_backoff 時間に達した後も再試行を継続できますが、アプリケーションが応答不能にならないように、一定時間が経過した後にリクエストが失敗するように設定することをおすすめします。たとえば、クライアントで 64 秒の maximum_backoff 時間が使用されている場合、この値に達した後は、クライアントは 64 秒ごとに再試行を繰り返します。その後、600 秒の deadline の後にクライアントは再試行を停止します。

クライアントの再試行の待ち時間の間隔や再試行の回数は、ユースケースとネットワークの状態によって異なります。たとえば、アプリケーションのモバイル クライアントでは、同じアプリケーションのデスクトップ クライアントに比べて、より多くの再試行回数とより長い再試行間隔が必要になる可能性があります。

maximum_backoff と再試行に対して許容される追加時間を合計した時間を超えたために再試行リクエストが失敗した場合は、サポートとヘルプにリストされているいずれかの方法で、エラーのレポートまたはログを作成してください。

次のステップ