Como enviar solicitações em lote

Neste documento, você verá como agrupar chamadas da API JSON em lote para reduzir o número de conexões HTTP que seu cliente precisa fazer ao acessar o Cloud Storage.

Visão geral

Cada conexão HTTP feita pelo cliente resulta em certa quantidade de sobrecarga. A API JSON do Cloud Storage é compatível com processamento em lote, para que seu cliente possa colocar várias chamadas de API em uma única solicitação HTTP.

Estes são exemplos de situações em que você pode usar as operações em lote:

  • Atualizar metadados, como permissões, em muitos objetos.
  • Como excluir muitos objetos.

Em cada caso, em vez de enviar cada chamada separadamente, você pode agrupá-las em uma única solicitação HTTP. Todas as solicitações internas precisam ser encaminhadas para a mesma API JSON do Cloud Storage.

Não inclua mais de 100 chamadas em uma única solicitação em lote. Se você precisar fazer mais chamadas do que isso, use várias solicitações em lote. O payload total da solicitação precisa ser menor que 10 MB.

Detalhes do lote

Uma solicitação em lote consiste em várias chamadas de API combinadas em uma solicitação HTTP, que pode ser enviada para o endpoint em lote do Cloud Storage, que é https://storage.googleapis.com/batch/storage/v1. Nesta seção, você verá a descrição em detalhes da sintaxe do lote e, em seguida, um exemplo.

Formato de uma solicitação em lote

Uma solicitação em lote é uma única solicitação HTTP padrão que contém várias chamadas da API JSON do Cloud Storage. Essa solicitação principal usa o tipo de conteúdo multipart/mixed. Na solicitação HTTP principal, há várias partes, cada uma com uma solicitação HTTP aninhada.

Cada parte começa com seu próprio cabeçalho HTTP Content-Type: application/http. A parte também pode ter um cabeçalho Content-ID opcional. Esses cabeçalhos marcam o início da parte, mas são separados da solicitação HTTP aninhada. Isso significa que, depois que o servidor desencapsula a solicitação em solicitações separadas, os cabeçalhos das partes são ignorados.

O corpo de cada parte é ele próprio uma solicitação HTTP completa, com o próprio verbo, URL, cabeçalhos e corpo. Essas solicitações HTTP precisam conter apenas a parte do caminho do URL; URLs completos podem ter um comportamento indefinido.

Os cabeçalhos HTTP da solicitação em lote externa, exceto os cabeçalhos Content-, como Content-Type, também se aplicam a todas as solicitações aninhadas. No entanto, se você especificar um determinado cabeçalho HTTP na solicitação externa e em uma solicitação aninhada, o valor do cabeçalho da solicitação aninhada modificará o valor do cabeçalho da solicitação em lote externa para essa solicitação específica.

Por exemplo, se você fornecer um cabeçalho Authorization para uma solicitação aninhada específica, esse cabeçalho será aplicado somente à solicitação que o especificou. Se você fornecer um cabeçalho Authorization para a solicitação externa, esse cabeçalho será aplicado a todas as solicitações aninhadas, a menos que elas o substituam por um cabeçalho Authorization próprio.

Ao receber a solicitação em lote, o Cloud Storage aplica os parâmetros e os cabeçalhos de consulta da solicitação externa (conforme apropriado) a cada parte e trata cada parte como se fosse uma solicitação HTTP separada.

Resposta a uma solicitação em lote

A resposta do Cloud Storage é uma resposta HTTP padrão única com um tipo de conteúdo multipart/mixed; cada parte dessa resposta principal é a resposta a uma das solicitações na solicitação em lote. A ordem das respostas é a mesma das solicitações.

Como todas as partes em uma solicitação, cada parte da resposta contém uma resposta HTTP completa, incluindo um código de status, cabeçalhos e corpo. E da mesma forma que as partes na solicitação, cada parte da resposta é precedida por um cabeçalho Content-Type que marca o início da parte. Para mais informações sobre códigos de status, consulte Códigos de erro e de status HTTP para a API JSON do Cloud Storage.

Se determinada parte da solicitação tiver um cabeçalho Content-ID, a parte correspondente da resposta terá um cabeçalho Content-ID correspondente. O cabeçalho Content-ID da resposta começa com response-, seguido pelo valor Content-ID usado na solicitação, conforme mostrado no exemplo.

Exemplo

O exemplo de lote a seguir atualiza os metadados personalizados de três objetos em example-bucket.

Exemplo de solicitação HTTP em lote

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==--

Bibliotecas de cliente

C++

A biblioteca de cliente C++ não é compatível com solicitações em lote.

C#

A biblioteca de cliente C# não é compatível com solicitações em lote.

Go

A biblioteca de cliente Go não oferece suporte a solicitações em lote.

Java

Para mais informações, consulte a documentação de referência da API Cloud Storage para Java.

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

A biblioteca de cliente do Node.js não aceita solicitações em lote.

PHP

A biblioteca de cliente PHP não aceita solicitações em lote.

Python

Para mais informações, consulte a documentação de referência da API Cloud Storage para Python.


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

Para saber como fazer uma solicitação em lote usando Ruby, consulte a documentação de referência da API Cloud Storage para Ruby.

Exemplo de resposta HTTP em lote

Esta é a resposta à solicitação de exemplo de HTTP da seção anterior:

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=--

Se a solicitação geral não estiver formatada corretamente e o Cloud Storage não conseguir analisá-la em subsolicitações, você receberá um erro 400. Caso contrário, o Cloud Storage retornará um código de status 200, mesmo que algumas ou todas as subsolicitações falhem.

Quando a solicitação geral retorna com um código de status 200, a resposta contém resultados para cada subsolicitação, incluindo um código de status para cada uma, que indica se a subsolicitação foi bem-sucedida ou não. Por exemplo, ao excluir objetos em lote, cada subsolicitação bem-sucedida contém um código de status 204 No Content.