재시도 전략

이 페이지에서는 Cloud Storage에 대한 실패한 요청의 잘린 지수 백오프와 같은 재시도 전략을 설명합니다.

개요

Cloud Console 및 대부분의 클라이언트 라이브러리와 같은 많은 Cloud Storage 도구는 자동으로 재시도 전략을 사용하므로 일반적으로 직접 구현할 필요가 없습니다. 자체적으로 재시도 전략을 구현하는 경우에는 요청을 안전하게 재시도할 수 있는지 여부를 결정하는 두 가지 요소가 있습니다.

  1. 요청에서 받은 응답
  2. 요청의 멱등성

이러한 요소 및 사용할 권장 재시도 알고리즘에 대한 설명은 재시도 전략 구현을 참조하세요.

Cloud Storage 도구별 재시도 전략

아래의 탭을 클릭하여 각 Cloud Storage 도구의 재시도 전략 권장사항을 확인하세요.

Console

Cloud Console이 사용자를 대신하여 Cloud Storage에 요청을 보내고 필요한 백오프를 처리합니다.

gsutil

gsutil은 별도로 조치를 취하지 않아도 응답 섹션에 나열된 오류를 재시도합니다. 다음과 같은 다른 오류에 대해 조치를 취해야 할 수 있습니다.

  • 사용자 인증 정보가 잘못되었거나 권한이 부족합니다.

  • 프록시 구성에 문제가 있어 네트워크에 연결할 수 없습니다.

  • -m 최상위 플래그를 사용하는 명령어 내에서 개별 작업이 실패합니다.

재시도 가능한 오류의 경우 gsutil은 잘린 바이너리 지수 백오프 전략을 사용하여 요청을 재시도합니다. 기본적으로 gsutil은 약 10분 동안 1+2+4+8+16+32+60...초에 걸쳐 23회까지 다시 시도합니다.

  • 요청이 실패하면 [0..1]초와 임의의 재시도 시간 동안 기다린 후
  • 요청이 다시 실패하면 [0..2]초 사이에 임의의 마침표를 요청한 후 다시 시도합니다.
  • 요청이 다시 실패하면 [0..4]초 내의 무작위 기간을 기다린 후 다시 시도합니다.
  • 그러면 최대 23회의 재시도, 각 재시도 기간은 기본적으로 최대 60초로 제한됩니다.

.boto 구성 파일의 "[Boto]" 섹션에서 num_retriesmax_retry_delay 구성 변수를 수정하여 개별 재시도의 재시도 횟수 및 최대 지연 시간을 구성할 수 있습니다.

gsutil cprsync 명령어를 사용하여 데이터를 전송할 때 gsutil은 재개 가능한 전송 형태로 추가 재시도 기능을 제공합니다.

클라이언트 라이브러리

C++

C++ 클라이언트 라이브러리는 기본적으로 지수 백오프를 사용합니다.

C#

C# 클라이언트 라이브러리는 기본적으로 지수 백오프를 사용합니다.

Go

Go 클라이언트 라이브러리는 기본적으로 지수 백오프를 사용합니다.

자바

자바 클라이언트 라이브러리는 기본적으로 지수 백오프를 사용합니다.

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를 통한 작업은 지수 백오프에 대해 다음 설정을 사용합니다.

설정 기본값(초)
자동으로 다시 시도
최대 재시도 횟수 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

작업의 하위 집합은 특정한 선택적 인수를 포함하는 경우에만 멱등성을 가집니다. 조건부로 재시도해도 안전한 작업은 기본적으로 조건 케이스가 통과된 경우에만 재시도됩니다. 현재 이러한 조건에는 다음이 포함됩니다.

  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED

    • generation 또는 if_generation_match가 메서드에 인수로 전달되면 재시도해도 안전합니다. 메서드가 이러한 두 매개변수 중 하나만 허용합니다.
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED

    • if_metageneration_match가 메서드에 인수로 전달되면 재시도해도 안전합니다.
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

    • 메서드가 JSON 요청 본문에 etag를 삽입하면 재시도해도 안전합니다. HMACKeyMetadata.update()의 경우 etag를 HMACKeyMetadata 객체 자체에서 설정해야 합니다. 다른 클래스의 set_iam_policy() 메서드의 경우 etag를 메서드로 전달되는 'policy' 인수에서 설정해야 합니다.

재시도 정책

재시도해도 안전하거나 조건부로 안전한 작업에서는 메서드 서명에 retry 매개변수가 추가됩니다. 해당 매개변수의 기본값은 다음 중 하나입니다.

  • DEFAULT_RETRY
  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

기본 재시도 동작을 수정하려면 with_XXX 메서드로 google.cloud.storage.retry.DEFAULT_RETRY 객체를 호출하여 이 객체의 복사본을 만듭니다. with_predicate는 업로드 및 다운로드와 같이 페이로드 데이터를 가져오거나 객체로 전송하는 작업에 지원되지 않습니다. 속성을 하나씩 수정하는 것이 좋습니다. 자세한 내용은 google-api-core 재시도 참조를 확인하세요.

나만의 조건부 재시도를 구성하려면 ConditionalRetryPolicy 객체를 만들고 커스텀 Retry 객체를 DEFAULT_RETRY_IF_GENERATION_SPECIFIED, DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, 또는 DEFAULT_RETRY_IF_ETAG_IN_JSON로 래핑합니다.

다음은 맞춤설정된 재시도의 예시입니다.

  • blob.reload()는 기본적으로 DEFAULT_RETRY를 사용합니다. 이를 재정의하여 함수가 전혀 재시도되지 않도록 하려면 blob.reload(retry=None)로 호출합니다.

  • bucket.update()는 기본적으로 DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED를 사용합니다. 메타 세대 번호가 지정되지 않은 경우에도 함수가 재시도되도록 이를 재정의하려면 다음과 같이 호출합니다.

    from google.cloud.storage.retry import DEFAULT_RETRY
    bucket.update(retry=DEFAULT_RETRY)
  • bucket.list_blobs()는 기본적으로 DEFAULT_RETRY를 사용합니다. 이를 재정의하여 API 호출이 기본값인 120초 대신 20초 기한으로 재시도되도록 하려면 다음과 같이 호출합니다.

    from google.cloud.storage.retry import DEFAULT_RETRY
    modified_retry = DEFAULT_RETRY.with_deadline(20)
    bucket.list_blobs(retry=modified_retry)

Ruby

Ruby 클라이언트 라이브러리는 기본적으로 지수 백오프를 사용합니다.

REST API

JSON 또는 XML API를 직접 호출할 때는 지수 백오프 알고리즘을 사용하여 자체 재시도 전략을 구현해야 합니다.

재시도 전략 구현

이 섹션에서는 자체 재시도 전략을 구축할 때 고려해야 할 요소 및 권장되는 재시도 알고리즘에 대해 설명합니다.

응답

요청으로부터 수신하는 응답은 요청을 재시도하는 것이 유용한지 여부를 나타냅니다. 일시적인 문제와 관련된 응답은 일반적으로 재시도할 수 있습니다. 반면 영구적 오류와 관련된 응답은 요청을 다시 시도하기 전에 승인 또는 구성 변경과 같은 변경을 수행해야 한다는 것을 나타냅니다. 다음 응답은 재시도에 유용한 일시적인 문제를 나타냅니다.

  • HTTP 408, 429, 5xx 응답 코드입니다.
  • 소켓 시간 초과 및 TCP 연결 해제

자세한 내용은 JSONXML 상태 및 오류 코드를 참조하세요.

멱등성

멱등성 요청은 반복적으로 수행될 수 있으며 대상 리소스를 항상 동일한 종료 상태로 유지할 수 있음을 의미합니다. 예를 들어 나열 요청은 리소스를 수정하지 않으므로 항상 나열 요청이 멱등성을 갖습니다. 반면 새로운 Pub/Sub 알림 만들기는 요청이 성공할 때마다 새 알림 ID를 만들기 때문에 멱등적이지 않습니다.

다음은 멱등성을 충족하는 조건의 예시입니다.

  • 이 작업은 지속적으로 요청하더라도 대상 리소스에 동일하게 관찰 가능한 영향을 미칩니다.

  • 이 작업은 한 번만 성공합니다.

  • 작업은 대상 리소스 상태에 관찰 가능한 영향을 미치지 않습니다.

재시도할 수 있는 응답을 받으면 요청의 멱등성을 고려해야 합니다. 멱등성이 아닌 요청을 재시도하면 경합 상태 및 기타 충돌이 발생할 수 있기 때문입니다.

조건부 멱등성

요청의 하위 집합은 조건부 멱등성을 가집니다. 즉, 특정 선택적 인수를 포함하는 경우에만 멱등성을 가집니다. 조건부로 재시도해도 안전한 작업은 기본적으로 조건 케이스가 통과된 경우에만 재시도해야 합니다. Cloud Storage는 요청의 조건 케이스로 전제조건 및 ETag를 허용합니다.

작업의 멱등성

다음 표에는 각 멱등성 카테고리에 속하는 Cloud Storage 작업이 나와 있습니다.

멱등성 운영
항상 멱등
  • 모든 get 및 list 요청
  • 버킷 삽입 또는 삭제
  • 테스트 버킷 IAM 정책 및 권한
  • 보관 정책 잠그기
  • HMAC 키 또는 Pub/Sub 알림 삭제
조건부 멱등
  • IfMetagenerationMatch 또는 ETag를 HTTP 전제조건으로 버켓의 업데이트/패치 요청
  • IfMetagenerationMatch 또는 ETag를 HTTP 전제조건으로 객체의 업데이트/패치 요청
  • ETag를 HTTP 전제조건 또는 리소스 본문으로 버킷 IAM 정책 설정
  • HMAC 키를 HTTP 전제조건 또는 리소스 본문으로 업데이트
  • 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((2^n, random_number_milliseconds), maximum_backoff)입니다. 여기서 n은 반복(요청)마다 1씩 증가합니다.

  • random_number_milliseconds는 1,000밀리초 이하의 임의 숫자입니다. 이는 많은 클라이언트가 동기화되고 모든 요청이 한 번에 재시도되어 동기화된 웨이브로 요청을 보내는 경우를 피하는 데 도움이 됩니다. random_number_milliseconds 값은 각 재시도 요청 후 다시 계산됩니다.

  • maximum_backoff는 일반적으로 32 또는 64초입니다. 적절한 값은 사용 사례에 따라 다릅니다.

maximum_backoff 시간에 도달한 후에는 계속 재시도할 수 있지만 애플리케이션이 응답하지 않게 되는 것을 방지하려면 일정 시간 후 요청을 실패하는 것이 좋습니다. 예를 들어 클라이언트가 maximum_backoff 시간으로 64초를 사용하는 경우 이 값에 도달한 후 클라이언트는 64초마다 재시도할 수 있습니다. 그런 다음 클라이언트는 deadline 600초 후 재시도를 중지합니다.

클라이언트가 재시도 사이에 얼마나 오래 대기해야 하는지와 몇 번 재시도해야 하는지는 사용 사례와 네트워크 상태에 따라 다릅니다. 예를 들어 애플리케이션의 모바일 클라이언트는 동일한 애플리케이션의 데스크톱 클라이언트보다 더 자주, 더 긴 간격으로 재시도해야 할 수 있습니다.

maximum_backoff와 재시도할 수 있는 추가 시간이 지난 후 재시도 요청이 실패하면 지원 및 도움말에 나열된 방법 중 하나로 오류를 신고하거나 로깅합니다.

다음 단계