一括リクエストの送信

このドキュメントでは、JSON API 呼び出しをバッチ処理し、Cloud Storage へのアクセス時にクライアントが行う HTTP 接続の数を減らす方法について説明します。

概要

クライアントで HTTP 接続を行うたびに、ある程度のオーバーヘッドが発生します。Cloud Service JSON API では一括処理がサポートされており、クライアントで複数の API 呼び出しを 1 つの HTTP リクエストにまとめることができます。

バッチ処理は次のような状況で使用します。

  • 多くのオブジェクトで権限などのメタデータを更新する場合
  • 多くのオブジェクトを削除する場合

いずれの場合も、各呼び出しを個別に送信するのではなく、1 つの HTTP リクエストにまとめることができます。内部リクエストはすべて Cloud Storage JSON API に送信する必要があります。

1 つのバッチ リクエストには、100 を超える呼び出しを含めないでください。これよりも多くの呼び出しを行う必要がある場合は、複数のバッチ リクエストを使用します。バッチ リクエストのペイロードの合計は 10 MB 未満にする必要があります。

バッチ リクエストの詳細

バッチ リクエストは、複数の API 呼び出しを 1 つの HTTP リクエストにまとめたもので、API ディスカバリ ドキュメントで指定されている batchPath に送信できます。Cloud Storage のパスは /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 では未定義の動作が発生することがあります。

外側のバッチ リクエストの HTTP ヘッダーは、Content-Type などの Content- ヘッダーを除き、ネストされたすべてのリクエストに適用されます。ただし、外部リクエストとネストされたリクエストの両方で特定の 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 クライアント ライブラリはバッチ リクエストをサポートしていません。

Java

詳細については、Cloud Storage Java 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."""
    # 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 ステータス コードを返す場合、レスポンスにはステータス コードと各サブリクエストの結果が含まれ、サブリクエストが成功したかどうかを示します。

次のステップ

  • Google API ディスカバリ サービスで、API ディスカバリ ドキュメントの詳細と、そのドキュメントを使用して Google API の異なるバージョンに RESTful HTTP 呼び出しを行う方法を確認する。