일괄 요청 전송

이 문서에서는 JSON API 호출을 일괄 처리하여 Cloud Storage에 액세스할 때 클라이언트가 수행해야 하는 HTTP 연결 수를 줄이는 방법을 보여줍니다.

개요

클라이언트가 수행하는 각 HTTP 연결에는 어느 정도의 오버헤드가 수반됩니다. Cloud Storage JSON API는 일괄 처리를 지원하므로 클라이언트에서 단일 HTTP 요청에 여러 개의 API 호출을 배치할 수 있습니다.

다음과 같은 경우에 일괄 처리를 사용할 수 있습니다.

  • 여러 객체에 대한 권한 등의 메타데이터를 업데이트합니다.
  • 많은 객체를 삭제합니다.

각각의 경우 각 호출을 개별적으로 보내는 대신 단일 HTTP 요청으로 그룹화할 수 있습니다. 내부 요청은 모두 Cloud Storage JSON API로 이동해야 합니다.

단일 일괄 요청에 호출을 100회를 초과하여 포함하지 마세요. 이보다 많은 호출이 필요하면 여러 개의 일괄 요청을 사용해야 합니다. 총 일괄 요청 페이로드는 10MB 미만이어야 합니다.

일괄 처리 세부정보

일괄 요청은 하나의 HTTP 요청으로 결합된 여러 API 호출로 구성되며, 이 요청을 Cloud Storage 일괄 엔드포인트https://storage.googleapis.com/batch/storage/v1로 보낼 수 있습니다. 이 섹션에서는 일괄 처리 구문을 세부적으로 설명하며 뒷부분에서 예시를 제시합니다.

일괄 요청의 형식

일괄 요청은 여러 개의 Cloud Storage JSON API 호출을 포함하는 단일 표준 HTTP 요청입니다. 이 기본 요청에는 multipart/mixed 콘텐츠 유형이 사용됩니다. 기본 HTTP 요청 내에는 중첩된 HTTP 요청이 각각 포함된 여러 부분이 있습니다.

각 부분은 자체 Content-Type: application/http HTTP 헤더로 시작됩니다. 또한 이 부분은 선택적인 Content-ID 헤더를 포함할 수 있습니다. 이러한 헤더는 해당 부분의 시작을 표시하지만 중첩된 HTTP 요청과 별개입니다. 즉, 서버에서 일괄 요청을 개별 요청으로 해체하면 부분 헤더는 무시됩니다.

각 부분의 본문은 자체 동사와 URL, 헤더, 본문을 포함하며 그 자체로 완전한 HTTP 요청입니다. 이러한 HTTP 요청은 URL의 경로 부분만 포함해야 하며, 전체 URL은 정의되지 않은 동작을 포함할 수 있습니다.

Content-Type과 같은 Content- 헤더를 제외하고 외부 일괄 요청에 대한 HTTP 헤더가 모든 중첩된 요청에도 적용됩니다. 하지만 외부 요청 및 중첩된 요청 모두에서 특정 HTTP 헤더를 지정할 경우에는 중첩된 요청의 헤더 값이 특정 요청에 대한 외부 일괄 요청 헤더의 값을 재정의합니다.

예를 들어 특정 중첩된 요청에 대해 Authorization 헤더를 제공할 경우 해당 헤더가 지정된 요청에만 적용됩니다. 외부 요청에 대해 Authorization 헤더를 제공하는 경우 자체 Authorization 헤더로 재정의하지 않는 한 해당 헤더가 모든 중첩된 요청에 적용됩니다.

Cloud Storage가 일괄 요청을 수신하면 외부 요청의 쿼리 매개변수와 헤더를 각 부분에 적절히 적용한 다음 각 부분을 개별 HTTP 요청처럼 취급합니다.

일괄 요청 응답

Cloud Storage 응답은 multipart/mixed 콘텐츠 유형의 단일 표준 HTTP 응답입니다. 이러한 기본 응답의 각 부분은 일괄 요청의 요청 중 하나에 대한 응답입니다. 응답 순서는 요청과 동일합니다.

요청의 모든 부분과 마찬가지로 각 응답 부분에는 상태 코드, 헤더, 본문을 포함한 완전한 HTTP 응답이 포함되어 있습니다. 또한 요청의 부분과 마찬가지로 각 응답 부분 앞에는 Content-Type 헤더가 붙어 부분의 시작을 표시합니다. 상태 코드에 대한 자세한 내용은 Cloud Storage JSON API의 HTTP 상태 및 오류 코드를 참조하세요.

요청의 특정 부분에 Content-ID 헤더가 포함된 경우, 응답의 해당 부분에 일치하는 Content-ID 헤더가 포함됩니다. 응답의 Content-ID 헤더는 예시에 표시된 대로 요청에 사용된 response- 값으로 이어지는 Content-ID로 시작합니다.

다음 일괄 처리 예시는 example-bucket에서 3개 객체에 대해 커스텀 메타데이터를 업데이트합니다.

일괄 HTTP 요청 예

HTTP

POST /batch/storage/v1 HTTP/1.1
Host: storage.googleapis.com
Content-Length: 960
Content-Type: multipart/mixed; boundary="===============7330845974216740156=="
Authorization: Bearer ya29.AHES6ZRVmB7fkLtd1XTmq6mo0S1wqZZi3-Lh_s-6Uw7p8vtgSwg

--===============7330845974216740156==
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: <b29c5de2-0db4-490b-b421-6a51b598bd22+1>

PATCH /storage/v1/b/example-bucket/o/obj1 HTTP/1.1
Content-Type: application/json
accept: application/json
content-length: 31

{"metadata": {"type": "tabby"}}
--===============7330845974216740156==
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: <b29c5de2-0db4-490b-b421-6a51b598bd22+2>

PATCH /storage/v1/b/example-bucket/o/obj2 HTTP/1.1
Content-Type: application/json
accept: application/json
content-length: 32

{"metadata": {"type": "tuxedo"}}
--===============7330845974216740156==
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: <b29c5de2-0db4-490b-b421-6a51b598bd22+3>

PATCH /storage/v1/b/example-bucket/o/obj3 HTTP/1.1
Content-Type: application/json
accept: application/json
content-length: 32

{"metadata": {"type": "calico"}}
--===============7330845974216740156==--

클라이언트 라이브러리

C++

C++ 클라이언트 라이브러리는 일괄 요청을 지원하지 않습니다.

C#

C# 클라이언트 라이브러리는 일괄 요청을 지원하지 않습니다.

Go

Go 클라이언트 라이브러리는 일괄 요청을 지원하지 않습니다.

자바

자세한 내용은 Cloud Storage 자바 API 참조 문서를 확인하세요.

import com.google.api.gax.paging.Page;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageBatch;
import com.google.cloud.storage.StorageOptions;
import java.util.HashMap;
import java.util.Map;

public class BatchSetObjectMetadata {
  public static void batchSetObjectMetadata(
      String projectId, String bucketName, String directoryPrefix) {
    // The ID of your GCP project
    // String projectId = "your-project-id";

    // The ID of your GCS bucket
    // String bucketName = "your-unique-bucket-name";

    // The directory prefix. All objects in the bucket with this prefix will have their metadata
    // updated
    // String directoryPrefix = "yourDirectory/";

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
    Map<String, String> newMetadata = new HashMap<>();
    newMetadata.put("keyToAddOrUpdate", "value");
    Page<Blob> blobs =
        storage.list(
            bucketName,
            Storage.BlobListOption.prefix(directoryPrefix),
            Storage.BlobListOption.currentDirectory());
    StorageBatch batchRequest = storage.batch();

    // Add all blobs with the given prefix to the batch request
    for (Blob blob : blobs.iterateAll()) {
      batchRequest.update(blob.toBuilder().setMetadata(newMetadata).build());
    }

    // Execute the batch request
    batchRequest.submit();

    System.out.println(
        "All blobs in bucket "
            + bucketName
            + " with prefix '"
            + directoryPrefix
            + "' had their metadata updated.");
  }
}

Node.js

Node.js 클라이언트 라이브러리는 일괄 요청을 지원하지 않습니다.

PHP

PHP 클라이언트 라이브러리는 일괄 요청을 지원하지 않습니다.

Python

자세한 내용은 Cloud Storage Python API 참조 문서를 확인하세요.


from google.cloud import storage


def batch_request(bucket_name, prefix=None):
    """
    Use a batch request to patch a list of objects with the given prefix in a bucket.

    Note that Cloud Storage does not support batch operations for uploading or downloading.
    Additionally, the current batch design does not support library methods whose return values
    depend on the response payload.
    See https://cloud.google.com/python/docs/reference/storage/latest/google.cloud.storage.batch
    """
    # The ID of your GCS bucket
    # bucket_name = "my-bucket"
    # The prefix of the object paths
    # prefix = "directory-prefix/"

    client = storage.Client()
    bucket = client.bucket(bucket_name)

    # Accumulate in a list the objects with a given prefix.
    blobs_to_patch = [blob for blob in bucket.list_blobs(prefix=prefix)]

    # Use a batch context manager to edit metadata in the list of blobs.
    # The batch request is sent out when the context manager closes.
    # No more than 100 calls should be included in a single batch request.
    with client.batch():
        for blob in blobs_to_patch:
            metadata = {"your-metadata-key": "your-metadata-value"}
            blob.metadata = metadata
            blob.patch()

    print(
        f"Batch request edited metadata for all objects with the given prefix in {bucket.name}."
    )

Ruby

Ruby를 사용하여 일괄 요청을 수행하는 방법은 Cloud Storage Ruby API 참조 문서를 참조하세요.

일괄 HTTP 응답 예

이전 섹션의 예시 HTTP 요청에 대한 응답입니다.

HTTP/1.1 200 OK
Content-Type: multipart/mixed; boundary=batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 3767

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Content-Type: application/http
Content-ID: <response-b29c5de2-0db4-490b-b421-6a51b598bd22+1>

HTTP/1.1 200 OK
ETag: "lGaP-E0memYDumK16YuUDM_6Gf0/V43j6azD55CPRGb9b6uytDYl61Y"
Content-Type: application/json; charset=UTF-8
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 846

{
 "kind": "storage#object",
 "id": "example-bucket/obj1/1495822576643790",
 .
 .
 .
 "metadata": {
  "type": "tabby"
  },
  .
  .
  .
}

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Content-Type: application/http
Content-ID: <response-b29c5de2-0db4-490b-b421-6a51b598bd22+2>

HTTP/1.1 200 OK
ETag: "lGaP-E0memYDumK16YuUDM_6Gf0/91POdd-sxSAkJnS8Dm7wMxBSDKk"
Content-Type: application/json; charset=UTF-8
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 846

{
 "kind": "storage#object",
 "id": "example-bucket/obj2/1495822576643790",
 .
 .
 .
 "metadata": {
  "type": "tuxedo"
  },
  .
  .
  .
}

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Content-Type: application/http
Content-ID: <response-b29c5de2-0db4-490b-b421-6a51b598bd22+3>

HTTP/1.1 200 OK
ETag: "lGaP-E0memYDumK16YuUDM_6Gf0/d2Z1F1_ZVbB1dC0YKM9rX5VAgIQ"
Content-Type: application/json; charset=UTF-8
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 846

{
 "kind": "storage#object",
 "id": "example-bucket/obj3/1495822576643790",
 .
 .
 .
 "metadata": {
  "type": "calico"
  },
  .
  .
  .
}

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=--

전체 요청의 형식이 올바르지 않고 Cloud Storage에서 요청을 하위 요청으로 파싱할 수 없는 경우 400 오류가 발생합니다. 그렇지 않으면 하위 요청의 일부 또는 전부가 실패하더라도 Cloud Storage에서 200 상태 코드를 반환합니다.

전체 요청이 200 상태 코드와 함께 반환되면 응답에 하위 요청의 성공 또는 실패 여부를 나타내는 각각의 상태 코드를 포함한 각 하위 요청의 결과가 포함됩니다. 예를 들어 객체를 일괄 삭제할 때 성공한 각 하위 요청에는 204 No Content 상태 코드가 포함됩니다.