요청 전제조건

이 페이지에서는 리소스가 예기치 않은 상태일 때 리소스에 요청이 적용되지 않도록 방지하는 요청 전제조건을 설명합니다.

소개

전제조건이 Cloud Storage에 대한 요청에 사용되는 경우 대상 리소스가 전제조건에 정의된 기준을 충족하는 경우에만 요청이 진행됩니다. 전제조건 확인은 버킷 또는 객체가 예상된 상태인지 확인함으로써 안전한 읽기-수정-쓰기 업데이트 및 조건부 작업을 수행할 수 있도록 합니다.

전제조건은 업로드, 삭제 또는 메타데이터 업데이트와 같은 변형 요청에서 경합 상태를 방지하는 데 자주 사용됩니다. 경합 상태는 동일 요청이 반복적으로 전송되거나 독립적인 프로세스에서 각각 동일한 리소스를 수정하려고 시도할 때 발생할 수 있습니다. 자세한 내용은 경합 상태 및 데이터 손상 예시를 참조하세요. 전제조건은 연속된 요청에서 객체 메타데이터 및 데이터를 검색할 때 종종 사용되므로 두 요청 사이의 시간에 객체가 변경되지 않았는지 확인합니다.

전제조건 기준

Cloud Storage는 전제조건에서 변경할 수 없는 여러 리소스 속성을 사용합니다.

다음 표에는 JSON API 및 XML API에서 지원하는 전제조건 목록이 나와 있습니다.

JSON API XML API 설명
ifGenerationMatch 쿼리 매개변수 x-goog-if-generation-match 헤더 대상 리소스의 generation이 전제조건에서 사용된 값과 일치하면 요청이 진행됩니다. 값이 일치하지 않으면 요청이 412 Precondition Failed 응답과 함께 실패합니다.
ifMetagenerationMatch 쿼리 매개변수 x-goog-if-metageneration-match 헤더 대상 리소스의 metageneration이 전제조건에서 사용된 값과 일치하면 요청이 진행됩니다. 값이 일치하지 않으면 요청이 412 Precondition Failed 응답과 함께 실패합니다.
ifGenerationNotMatch 쿼리 매개변수 N/A 대상 리소스의 generation이 전제조건에서 사용된 값과 일치하지 않으면 요청이 진행됩니다. 값이 일치하면 304 Not Modified 응답과 함께 요청이 실패합니다.
ifMetagenerationNotMatch 쿼리 매개변수 N/A 대상 리소스의 metageneration이 전제조건에서 사용된 값과 일치하지 않으면 요청이 진행됩니다. 값이 일치하면 304 Not Modified 응답과 함께 요청이 실패합니다.
If-Match 헤더 If-Match 헤더 데이터를 검색하는 요청에 적용 가능합니다. 대상 리소스의 ETag이 전제조건에서 사용된 값과 일치하면 요청이 진행됩니다. 값이 일치하지 않으면 요청이 412 Precondition Failed 응답과 함께 실패합니다.
If-None-Match 헤더 If-None-Match 헤더 데이터를 검색하는 요청에 적용 가능합니다. 대상 리소스의 ETag이 전제조건에서 사용된 값과 일치하지 않으면 요청이 진행됩니다. 값이 일치하면 304 Not Modified 응답과 함께 요청이 실패합니다.
N/A If-Modified-Since 헤더 대상 리소스에 전제조건에서 사용된 값 이후 Last-Modified 날짜가 있으면 요청이 진행됩니다. 대상 리소스가 이 전제조건을 충족하지 않으면 요청이 304 Not Modified 응답과 함께 실패합니다.
N/A If-Unmodified-Since 헤더 대상 리소스에 전제조건에서 사용된 값과 같거나 이전인 Last-Modified 날짜가 있으면 요청이 진행됩니다. 대상 리소스가 이 전제조건을 충족하지 않으면 요청이 412 Precondition Failed 응답과 함께 실패합니다.

객체 조합 전제조건

객체 조합을 수행할 때 JSON APIXML API가 다음을 지원합니다.

  • 대상 객체의 세대 일치 및 메타 세대 일치 전제 조건

  • 각 소스 객체의 세대 일치 전제 조건. 이 전제 조건을 사용하면 독립적인 프로세스가 조합의 의도된 구성요소 중 하나를 덮어쓰는 경우에 잘못된 구성요소가 사용되는 것을 방지합니다. 전제 조건을 사용하는 경우 덮어쓰기가 수행되면 compose 작업이 412 Precondition Failed 응답과 함께 실패합니다.

객체 복사 전제조건

Cloud Storage 내에서 객체를 복사하거나 재작성할 때 JSON APIXML API 모두 대상 객체에 표준 전제조건을 사용할 수 있습니다. 각 API에는 소스 객체에 대한 추가적인 전제 조건이 지원됩니다.

  • JSON API는 ifSource라는 프리픽스가 붙은 쿼리 매개변수를 사용하여 지정된 소스 객체의 세대 및 메타 세대 전제 조건을 지원합니다.

  • XML API에서 지원하는 모든 전제조건을 소스 객체에 사용할 수 있습니다. 이러한 전제조건은 x-goog-copy-source- 프리픽스가 붙은 헤더에 지정됩니다.

세대 일치 전제 조건의 0

세대 일치 전제 조건에서는 0 값을 특수한 경우로 허용합니다. 값이 0인 세대 일치 전제 조건이 요청에 포함된 경우 버킷에 지정된 이름의 객체가 없거나 이전 버전의 객체만 있는 경우에만 요청이 진행됩니다. 지정된 이름의 서비스 중인 버전이 있으면 상태 코드 412 Precondition Failed와 함께 요청이 실패합니다.

권장사항 및 고려사항

  • 단일 요청에서 여러 전제조건을 사용할 수 있습니다. 전제조건이 충족되지 않으면 전체 요청이 실패합니다.

  • 버킷에는 세대 번호가 없지만 메타 세대 번호가 있습니다. 버킷 요청에 세대 번호를 지정하는 전제조건을 사용하면 안 됩니다.

  • 객체 요청에 메타 세대 전제 조건을 사용하는 경우 항상 세대 전제 조건도 사용해야 합니다. 이렇게 하면 전제 조건을 통과하는 메타 세대 번호가 우연히 있는 다른 객체의 요청이 성공하는 것을 방지합니다.

  • 서비스 중이거나 현재 버전이 아닌 객체 버전이 모두 있는 버킷의 경우 세대 번호가 해당 요청에 명시적으로 포함된 경우가 아닌 한 객체 요청이 현재 버전이 아닌 버전에 적용되지 않습니다. 즉, 전제조건을 사용하는 일반 요청의 경우, 현재 버전이 아닌 버전이 전제조건과 일치하는지 여부에 관계없이 서비스 중인 버전이 전제조건과 일치하지 않으면 요청이 실패합니다.

  • 일반적으로 ETag 전제조건 대신 세대 전제조건과 메타 세대 전제조건을 사용해야 합니다. 세대 번호와 메타 세대 번호는 메타데이터 변경을 포함하여 모든 객체 업데이트를 추적하므로 ETag보다 강력한 보장을 제공합니다. 또한 세대 번호와 메타 세대 번호는 API 간에 일관되지만 ETag는 일관되지 않습니다.

  • XML API 멀티파트 업로드에서는 전제조건을 사용할 수 없습니다. 그렇게 하면 400 NotImplemented 오류가 발생합니다.

전제조건의 비용

전제조건을 활용하는 많은 아키텍처에서는 현재 세대 및/또는 메타 세대 번호를 파악하기 위해 기본 요청 전에 객체 메타데이터 요청을 수행해야 합니다.

  • 추가 요청으로 인해 왕복이 한 번 더 추가되어 네트워크로 인한 전체 작업 지연 시간이 두 배까지 늘어날 수 있으며, 이는 지연 시간에 민감한 작업의 경우 중요한 요소가 될 수 있습니다.

애플리케이션에 따라 다음과 같이 사전 조건 사용에 따른 영향을 줄일 수 있습니다.

  • 전제조건에서 사용할 정확한 번호를 미리 알 수 있도록 객체의 세대 및 메타 세대 번호를 로컬에 저장합니다.
  • if-generation-match:0 전제조건을 사용할 시점을 미리 알 수 있도록 새로 생성되는 객체를 애플리케이션에 알립니다.

예시: 전제조건 사용

다음 예시에서는 요청에 세대 일치 전제 조건을 사용하여 객체를 업로드합니다. 요청을 진행하려면 지정된 이름의 버킷에 저장된 기존 객체가 있어야 하며 기존 객체의 세대 번호는 전제조건에 제공된 번호와 일치해야 합니다.

명령줄

일반 명령어와 함께 --if-generation-match 플래그를 사용합니다.

gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME --if-generation-match=GENERATION

각 항목의 의미는 다음과 같습니다.

  • GENERATION은 교체할 객체의 의도된 세대 번호입니다. 예를 들면 1122334455667788입니다.

  • OBJECT_LOCATION은 객체의 로컬 경로입니다. 예를 들면 Desktop/dog.png입니다.

  • DESTINATION_BUCKET_NAME은 객체를 업로드할 버킷의 이름입니다. 예를 들면 my-bucket입니다.

JSON API

  1. OAuth 2.0 Playground에서 승인 액세스 토큰을 가져옵니다. 자체 OAuth 사용자 인증 정보를 사용하도록 Playground를 구성합니다. 자세한 내용은 API 인증을 참조하세요.
  2. cURL을 사용하여 POST 객체 요청으로 JSON API를 호출합니다.

    curl -X POST --data-binary @OBJECT_LOCATION \
      -H "Authorization: Bearer OAUTH2_TOKEN" \
      -H "Content-Type: OBJECT_CONTENT_TYPE" \
      "https://storage.googleapis.com/upload/storage/v1/b/BUCKET_NAME/o?uploadType=media&name=OBJECT_NAME"&ifGenerationMatch=GENERATION"

    각 항목의 의미는 다음과 같습니다.

    • OBJECT_LOCATION은 객체의 로컬 경로입니다. 예를 들면 Desktop/dog.png입니다.
    • OAUTH2_TOKEN은 1단계에서 생성한 액세스 토큰입니다.
    • OBJECT_CONTENT_TYPE은 객체의 콘텐츠 유형입니다. 예를 들면 image/png입니다.
    • BUCKET_NAME은 객체를 업로드할 버킷의 이름입니다. 예를 들면 my-bucket입니다.
    • OBJECT_NAME은 객체에 지정하려는 이름입니다. 예를 들면 dog.png입니다.
    • GENERATION은 교체할 객체의 의도된 세대 번호입니다. 예를 들면 1122334455667788입니다.

XML API

  1. OAuth 2.0 Playground에서 승인 액세스 토큰을 가져옵니다. 자체 OAuth 사용자 인증 정보를 사용하도록 Playground를 구성합니다. 자세한 내용은 API 인증을 참조하세요.
  2. cURL을 사용하여 PUT 객체 요청으로 XML API를 호출합니다.

    curl -X PUT --data-binary @OBJECT_LOCATION \
      -H "Authorization: Bearer OAUTH2_TOKEN" \
      -H "Content-Type: OBJECT_CONTENT_TYPE" \
      -H "x-goog-if-generation-match: GENERATION" \
      "https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME"

    각 항목의 의미는 다음과 같습니다.

    • OBJECT_LOCATION은 객체의 로컬 경로입니다. 예를 들면 Desktop/dog.png입니다.
    • OAUTH2_TOKEN은 1단계에서 생성한 액세스 토큰입니다.
    • OBJECT_CONTENT_TYPE은 객체의 콘텐츠 유형입니다. 예를 들면 image/png입니다.
    • GENERATION은 교체할 객체의 의도된 세대 번호입니다. 예를 들면 1122334455667788입니다.
    • BUCKET_NAME은 객체를 업로드할 버킷의 이름입니다. 예를 들면 my-bucket입니다.
    • OBJECT_NAME은 객체에 지정하려는 이름입니다. 예를 들면 dog.png입니다.

전제조건 사용 시나리오

다음 시나리오에서는 전제 조건의 이점을 활용하는 경합 상태 및 캐싱 예시를 살펴봅니다.

여러 번 요청 재시도

Cloud Storage는 분산형 시스템입니다. 네트워크 또는 서비스 상태로 인해 요청이 실패할 수 있으므로 실패를 재시도할 때 지수 백오프를 적용하는 것이 좋습니다. 그러나 분산형 시스템의 특성으로 인해 이러한 재시도가 예기치 못한 동작을 일으키는 경우도 있습니다.

버킷 중 하나에 저장된 file.txt 객체를 삭제하려는 경우를 가정해 보겠습니다. 그런 다음에 이름이 같은 새 객체를 버킷에 추가하려고 합니다. 이를 위해 객체를 삭제하는 삭제 요청을 실행합니다. 하지만 중간 라우터 연결이 일시적으로 끊기는 등 네트워크 상태로 인해 요청이 Cloud Storage에 도달하지 못함으로써 응답을 받지 못할 수 있습니다.

첫 번째 요청에 대한 응답을 받지 못했기 때문에 객체에 대한 두 번째 삭제 요청을 실행합니다. 이번에는 성공하고 삭제되었다는 응답을 받습니다. 1분 후에 새 file.txt를 업로드합니다. 그러면 업로드가 성공합니다.

연결이 끊겼던 라우터가 나중에 다시 연결되고 손실된 것처럼 보였던 첫 번째 삭제 요청을 Cloud Storage에 보내면 경합 상태가 발생합니다. 이 요청이 Cloud Storage에 도착하면 새로운 file.txt가 있기 때문에 실제로 삭제가 이루어집니다. Cloud Storage는 삭제에 성공했다는 응답을 보내는데, 클라이언트는 더 이상 이 응답을 수신하기 위해 대기하지 않기 때문에 응답이 수신되지 않습니다. 결국 의도와는 달리 새로 업로드한 파일도 삭제될 뿐만 아니라, 두 번째 삭제가 이루어졌다는 사실조차 인지하지 못합니다.

다음의 다이어그램은 이 상황을 한 눈에 보여줍니다.

경합 상태 방지

위와 같은 상황이 발생하는 것을 방지하려면 현재 세대 번호를 확인하기 위해 먼저 file.txt의 메타데이터를 가져와야 합니다. 그런 다음 삭제 요청의 일부로 포함된 세대 일치 전제 조건에서 세대를 사용합니다. 전제조건을 사용하면 삭제 요청이 언제 Cloud Storage에 도달하는지 또는 전제조건이 포함된 삭제 요청이 몇 차례 전송되는지에 관계없이 해당 세대 번호의 객체 삭제됩니다. 다른 file.txt 세대를 삭제하려는 의도치 않은 시도는 응답 코드 412 Precondition Failed가 표시되면서 실패합니다.

비슷한 네트워크 중단이 삭제 요청 이후의 업로드 요청에 대해 경합 상태를 일으킬 수 있기 때문에 세대에서 업로드 요청에 포함된 세대 일치 전제 조건의 0을 사용하면 많은 경합 상태를 피할 수 있습니다. 이 전제 조건을 사용하면 업로드 재시도가 실수로 객체를 두 번 작성하는 것이 방지됩니다. 이 전제 조건은 현재 세대 번호의 객체가 없는 경우에만 요청을 진행하도록 허용하기 때문입니다.

이 전제조건을 사용하면 삭제 및 업로드 요청을 수행할 때 데이터가 실수로 손실되는 것을 방지할 수 있습니다. 다음 다이어그램에서 확인할 수 있습니다.

객체 메타데이터 연결

객체의 데이터와 메타데이터는 Cloud Storage의 객체를 함께 정의하는 별도의 항목입니다. 이들은 별도로 존재하므로 객체 메타데이터로 작업하는 동안 객체 데이터가 변경될 수 있습니다.

다음 사례들을 고려해보세요.

  • 두 가지 개별 요청으로 Cloud Storage에서 검색해야 하는 객체의 메타데이터와 데이터를 다운로드하려고 합니다. 먼저 객체 메타데이터를 요청하되 객체 데이터를 요청하려면 먼저 독립적인 프로세스나 사용자가 객체를 교체합니다. 객체 데이터에 대한 요청은 여전히 성공하지만 이제 이전 객체의 메타데이터와 새 객체의 데이터가 있습니다.

  • 객체의 메타데이터를 업데이트하여 객체의 현재 메타데이터를 검색해 현재 상태를 확인하려고 합니다. 원하는 수정사항으로 메타데이터 업데이트 요청을 보내려면 먼저 독립 프로세스나 사용자가 객체를 대체합니다. 새 객체의 메타데이터 변경 요청은 여전히 성공했지만 이제 의도와는 다른 객체 데이터와 연결되어 있습니다.

경합 상태 방지

이러한 상황이 발생하지 않도록 하려면 객체 메타데이터의 초기 요청에서 반환되는 세대 번호를 사용한 후 두 번째 요청에서 세대 일치 전제 조건에 이 값을 사용해야 합니다. 이렇게 하면 메타데이터가 데이터와 올바르게 일치하거나 두 번째 요청이 412 Precondition Failed 응답 코드가 표시되면서 실패하여 새 객체의 올바른 메타데이터를 요청할 수 있습니다.

첫 번째 요청과 두 번째 요청 간에 객체 메타데이터 변경이 우려되는 경우 초기 요청에 있는 메타 세대 번호를 복사하여 두 번째 요청의 메타 세대 일치 전제 조건에서 사용할 수도 있습니다.

로컬 사본 최신 상태

Cloud Storage에 저장된 객체의 로컬 사본이 있는 경우 로컬 복사본을 버킷에 저장된 사본에 맞게 최신 상태로 유지하려는 경우가 많습니다. 그러나 버킷에 저장된 객체가 변경되지 않는 경우 특히 객체가 큰 경우 다시 다운로드하는 데 시간과 리소스를 소비하지 않는 것이 좋습니다.

최신 상태인 콘텐츠가 불필요하게 다운로드되지 않도록 하려면 로컬 사본의 세대 번호를 다운로드 요청에 포함된 세대 불일치 전제 조건의 값으로 사용하면 됩니다.

  • 버킷의 데이터가 로컬 사본과 계속 일치하면 세대 번호가 일치하므로 전제조건이 실패합니다. 따라서 전체 요청이 304 Not Modified 응답과 함께 실패하고 데이터가 불필요하게 다운로드되지 않습니다.

  • 버킷의 데이터가 변경되면 세대 번호가 일치하지 않으며 전제조건이 성공합니다. 즉, 전체 요청이 정상적으로 진행되며 업데이트된 버전의 콘텐츠가 다운로드됩니다.

다음 단계