Solicitar condições prévias

Esta página discute as condições prévias da solicitação, que você usa para impedir que as solicitações sejam aplicadas a um recurso quando o recurso está em um estado inesperado.

Introdução

Quando as condições prévias são usadas em uma solicitação para o Cloud Storage, a solicitação só continuará se o recurso de destino atender aos critérios definidos nas condições predefinidas. As verificações de condição prévia garantem que um bucket ou objeto esteja no estado esperado, permitindo que você execute atualizações seguras de leitura/modificação/gravação e operações condicionais.

As condições prévias geralmente são usadas para evitar disputas em solicitações de mutação, como uploads, exclusões ou atualizações de metadados. Disputas podem surgir quando a mesma solicitação é enviada repetidamente ou quando processos independentes tentam modificar o mesmo recurso. Consulte Exemplos de disputas e corrupção de dados para mais informações. As condições prévias também são usadas com frequência ao recuperar metadados de objetos e dados em solicitações sucessivas, para garantir que o objeto não foi alterado no tempo entre as duas solicitações.

Critérios de condição prévia

O Cloud Storage suporta o uso de várias propriedades diferentes de recursos imutáveis nas condições prévias:

A tabela a seguir lista as condições prévias suportadas pelas APIs JSON e XML:

API JSON API XML Descrição
Parâmetro de consulta ifGenerationMatch Cabeçalho x-goog-if-generation-match A solicitação prosseguirá se o generation do recurso de destino corresponder ao valor usado na condição prévia. Se os valores não corresponderem, a solicitação falhará com uma resposta 412 Precondition Failed.
Parâmetro de consulta ifMetagenerationMatch Cabeçalho x-goog-if-metageneration-match A solicitação prosseguirá se o metageneration do recurso de destino corresponder ao valor usado na condição prévia. Se os valores não corresponderem, a solicitação falhará com uma resposta 412 Precondition Failed.
Parâmetro de consulta ifGenerationNotMatch N/A A solicitação prosseguirá se o generation do recurso de destino não corresponder ao valor usado na condição prévia. Se os valores corresponderem, a solicitação falhará com uma resposta 304 Not Modified.
Parâmetro de consulta ifMetagenerationNotMatch N/A A solicitação prosseguirá se o metageneration do recurso de destino não corresponder ao valor usado na condição prévia. Se os valores corresponderem, a solicitação falhará com uma resposta 304 Not Modified.
Cabeçalho If-Match Cabeçalho If-Match Aplicável a solicitações que recuperam dados. A solicitação prosseguirá se o ETag do recurso de destino corresponder ao valor usado na condição prévia. Se os valores não corresponderem, a solicitação falhará com uma resposta 412 Precondition Failed.
Cabeçalho If-None-Match Cabeçalho If-None-Match Aplicável a solicitações que recuperam dados. A solicitação prosseguirá se o ETag do recurso de destino não corresponder ao valor usado na condição prévia. Se os valores corresponderem, a solicitação falhará com uma resposta 304 Not Modified.
N/A Cabeçalho If-Modified-Since A solicitação prosseguirá se o recurso de destino tiver uma data Last-Modified após o valor usado na condição prévia. Se o recurso de destino não atender a essa condição prévia, a solicitação falhará com uma resposta 304 Not Modified.
N/A Cabeçalho If-Unmodified-Since A solicitação prosseguirá se o recurso de destino tiver uma data de Last-Modified anterior ou igual ao valor usado na condição prévia. Se o recurso de destino não atender a essa condição prévia, a solicitação falhará com uma resposta 412 Precondition Failed.

Pré-condições da composição do objeto

Ao executar a composição de objetos, tanto a API JSON quanto a API XML são compatíveis com:

  • As condições prévias de geração e correspondência de geração do objeto de destino.

  • A pré-condição de correspondência de geração para cada objeto de origem. O uso dessa condição impede o uso de componentes incorretos no caso em que um processo independente substitui um dos componentes pretendidos da composição. Se você usar condições prévias e essa substituição ocorrer, as operações compose falharão com uma resposta 412 Precondition Failed.

Pré-condições da cópia do objeto

Ao copiar ou reescrever um objeto no Cloud Storage, a API JSON e a API XML são compatíveis com o uso de condições prévias padrão do objeto de destino. Cada API tem suporte adicional de pré-condição para objetos de origem:

  • A API JSON é compatível com as condições prévias de geração e metageração do objeto de origem, que são especificadas usando parâmetros de consulta com o prefixo ifSource.

  • Todas as condições prévias compatíveis com a API XML podem ser usadas para o objeto de origem. Essas pré-condições são especificadas em cabeçalhos com o prefixo x-goog-copy-source-.

O valor 0 em uma condição prévia de correspondência de geração

A condição prévia de correspondência de geração aceita o valor 0 como um caso especial. Quando uma pré-condição de correspondência de geração com um valor de 0 é incluída em uma solicitação, ela só prosseguirá se não houver nenhum objeto com o nome especificado no bucket ou se houver apenas versão anteriores do objeto no bucket. Se houver uma versão ativa com o nome especificado, a solicitação falhará com um código de status de 412 Precondition Failed.

Práticas recomendadas e considerações

  • É possível usar várias condições prévias em uma única solicitação. Se alguma das condições prévias não for atendida, a solicitação geral falhará.

  • Os buckets não têm um número de geração, mas têm um número de metageração. Não use condições prévias que especifiquem um número de geração em uma solicitação de bucket.

  • Se você usar uma pré-condição de metageração em uma solicitação de objeto, use sempre uma pré-condição de geração. Isso impede que a solicitação seja bem-sucedida em um objeto diferente que tenha um número de metageração que transmita a condição prévia.

  • Para buckets com versões ativas e não atuais de objetos, as solicitações de objetos não se aplicam a versões não atuais, a menos que um número de geração seja explicitamente incluído no solicitação. Isso significa que, para uma solicitação geral que usa condições prévias, a solicitação falhará se a versão ativa não corresponder à condição prévia, independentemente de uma versão não atual corresponder ou não às condições prévias.

  • Em geral, use as condições prévias de geração e metageração em vez de pré-condições de ETag. Juntos, os números de geração e de metageração rastreiam todas as atualizações de objetos, incluindo alterações de metadados. Esse método é mais seguro que o uso de ETags. Além disso, os números de geração e metageração são consistentes em todas as APIs, enquanto as ETags não são.

  • As condições prévias não podem ser usadas em uploads de várias partes da API XML. A tentativa de fazer isso resultará em um erro.400 NotImplemented

Custo das condições prévias

Muitas arquiteturas que utilizam condições prévias exigem que você faça uma solicitação de metadados do objeto antes da solicitação principal para determinar o número atual de geração e/ou metageração:

  • Outra solicitação significa que é possível até dobrar a parte da rede da latência geral da operação adicionando uma viagem de ida e volta extra, o que pode ser um fator importante em operações afetadas pela latência.

Dependendo do seu aplicativo, há maneiras de reduzir o impacto por usar condições prévias. Por exemplo:

  • Armazenando os números de geração e metageração de seus objetos localmente para que você já saiba os números corretos para usar em sua condição prévia.
  • Ter conhecimento de quais objetos foram criados recentemente no aplicativo para que você saiba quando usar a condição prévia if-generation-match:0.

Exemplo: como usar uma condição prévia

O exemplo a seguir usa a condição prévia de correspondência de geração em uma solicitação para fazer upload de um objeto. Para que a solicitação prossiga, é necessário que haja um objeto preexistente armazenado no bucket com o nome especificado, e o número de geração do objeto preexistente precisa corresponder ao número fornecido na condição prévia:

Linha de comando

Use a sinalização --if-generation-match com o comando normal:

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

Em que:

  • GENERATION é o número de geração pretendido do objeto que você quer substituir. Por exemplo, 1122334455667788.

  • OBJECT_LOCATION é o caminho local do objeto. Por exemplo, Desktop/dog.png.

  • DESTINATION_BUCKET_NAME é o nome do bucket para o qual você está fazendo o upload do objeto. Por exemplo, my-bucket.

API JSON

  1. Ter a gcloud CLI instalada e inicializadapara gerar um token de acesso para o cabeçalho Authorization.

    Como alternativa, é possível criar um token de acesso usando o OAuth 2.0 Playground e incluí-lo no cabeçalho Authorization.

  2. Use cURL para chamar a API JSON com uma solicitação de Objeto POST:

    curl -X POST --data-binary @OBJECT_LOCATION \
      -H "Authorization: Bearer $(gcloud auth print-access-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"

    Em que:

    • OBJECT_LOCATION é o caminho local do objeto. Por exemplo, Desktop/dog.png.
    • OBJECT_CONTENT_TYPE é o tipo de conteúdo do objeto. Por exemplo, image/png.
    • BUCKET_NAME é o nome do bucket para o qual você está fazendo o upload do objeto. Por exemplo, my-bucket.
    • OBJECT_NAME é o nome que você quer dar ao objeto. Por exemplo, dog.png.
    • GENERATION é o número de geração pretendido do objeto que você quer substituir. Por exemplo, 1122334455667788.

API XML

  1. Ter a gcloud CLI instalada e inicializadapara gerar um token de acesso para o cabeçalho Authorization.

    Como alternativa, é possível criar um token de acesso usando o OAuth 2.0 Playground e incluí-lo no cabeçalho Authorization.

  2. Use cURL (em inglês) para chamar a API XML com uma solicitação de objeto PUT:

    curl -X PUT --data-binary @OBJECT_LOCATION \
      -H "Authorization: Bearer $(gcloud auth print-access-token)" \
      -H "Content-Type: OBJECT_CONTENT_TYPE" \
      -H "x-goog-if-generation-match: GENERATION" \
      "https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME"

    Em que:

    • OBJECT_LOCATION é o caminho local do objeto. Por exemplo, Desktop/dog.png.
    • OBJECT_CONTENT_TYPE é o tipo de conteúdo do objeto. Por exemplo, image/png.
    • GENERATION é o número de geração pretendido do objeto que você quer substituir. Por exemplo, 1122334455667788.
    • BUCKET_NAME é o nome do bucket para o qual você está fazendo o upload do objeto. Por exemplo, my-bucket.
    • OBJECT_NAME é o nome que você quer dar ao objeto. Por exemplo, dog.png.

Cenários para usar condições prévias

Os cenários a seguir mostram as disputas e exemplos de armazenamento em cache que se beneficiam do uso de condições prévias.

Várias tentativas de solicitação

O Cloud Storage é um sistema distribuído. Como as solicitações podem falhar devido a condições de rede ou serviço, a maneira recomendada de repetir falhas é com a espera exponencial. No entanto, por causa da natureza dos sistemas distribuídos, às vezes essas novas tentativas podem causar um comportamento inesperado.

Considere o seguinte caso: você quer excluir um objeto, file.txt, armazenado em um dos seus buckets. Depois disso, adicione um novo objeto com o mesmo nome ao bucket. Para isso, você emite uma solicitação de exclusão do objeto. No entanto, uma condição de rede, como um roteador intermediário que perde a conectividade temporariamente, impede que a solicitação chegue ao Cloud Storage e você não recebe uma resposta.

Como não recebeu uma resposta para a primeira solicitação, você emite uma segunda solicitação de exclusão do objeto, que é bem-sucedida, e recebe uma resposta de confirmação. Um minuto depois, você faz upload de um novo file.txt, e seu upload é concluído.

Uma disputa surge se o roteador que perdeu a conectividade subsequentemente recuperá-la e enviar sua solicitação de exclusão original, aparentemente perdida, para o Cloud Storage. Quando a solicitação chega ao Cloud Storage, ela é bem-sucedida porque há um novo file.txt presente. O Cloud Storage envia uma resposta que você não recebe porque seu cliente parou de detectá-lo. Não apenas o novo arquivo é excluído, ao contrário do que você queria, mas também você não está ciente da segunda exclusão.

O diagrama a seguir mostra o que aconteceu:

Como evitar a disputa

Para evitar que a situação acima ocorra, o primeiro passo é conseguir os metadados do file.txt para determinar a geração atual. Em seguida, você usa a geração em uma pré-condição de correspondência de geração, incluída como parte da solicitação de exclusão. O uso da condição prévia garante que apenas o objeto com esse número de geração específico seja excluído, independentemente de quando a solicitação chega ao Cloud Storage ou de quantas vezes ela é enviada. Todas as tentativas não intencionais de excluir uma geração diferente de file.txt falham com o código de resposta 412 Precondition Failed.

Como interrupções de rede semelhantes podem causar disputas para a solicitação de upload que acompanha a solicitação de exclusão, é possível evitar muitas delas usando o valor 0 em uma correspondência geração de condição prévia incluída na solicitação de upload. Usar essa condição prévia garante que as novas tentativas de upload não gravarão acidentalmente o objeto duas vezes porque a condição prévia permite que a solicitação seja bem-sucedida somente se não houver gerações atuais do objeto.

Com essas condições prévias, você protege seus dados de serem perdidos acidentalmente ao realizar solicitações de exclusão e upload. Isso pode ser visto no diagrama a seguir:

Associação de metadados do objeto

Os dados e metadados de um objeto são entidades separadas que, juntas, definem o objeto no Cloud Storage. Como eles existem separadamente, é possível que os dados do objeto mudem enquanto você trabalha com os metadados do objeto.

Veja os seguintes casos:

  • Você quer fazer o download dos metadados e dos dados de um objeto, que precisam ser recuperados do Cloud Storage em duas solicitações separadas. Você solicita os metadados do objeto primeiro, mas, antes de poder solicitar os dados do objeto, um processo ou usuário independente substitui o objeto. Sua solicitação para os dados do objeto ainda será bem-sucedida, mas agora você tem os metadados do objeto antigo e os dados do novo objeto.

  • Você quer atualizar os metadados de um objeto para recuperar os metadados atuais do objeto, a fim de determinar o estado atual deles. Antes de enviar a solicitação para atualizar os metadados com as modificações desejadas, um processo ou usuário independente substitui o objeto. Sua solicitação para alterar os metadados do novo objeto ainda é bem-sucedida, mas agora está associada a dados de objetos diferentes do que você pretendia.

Como evitar a disputa

Para evitar que essas situações ocorram, use o número de geração retornado na solicitação inicial para metadados de objeto e, em seguida, use esse valor em uma pré-condição de correspondência de geração na segunda solicitação. Isso garante que os metadados correspondam corretamente aos dados ou que a segunda solicitação falhe com um código de resposta 412 Precondition Failed, permitindo que você solicite os metadados corretos para o novo objeto.

Se você acredita que os metadados de objetos podem mudar entre a primeira e a segunda solicitação, também é possível copiar o número de metageração encontrado na solicitação inicial e usá-lo em uma pré-condição de correspondência de metageração na segunda solicitação.

Atualização da cópia local

Nos casos em que você tem uma cópia local de um objeto armazenado no Cloud Storage, geralmente quer que sua cópia local permaneça atualizada com a cópia armazenada no seu bucket. No entanto, se o objeto armazenado no bucket não for alterado, não perca tempo e recursos fazendo o download novamente, especialmente se o objeto for grande.

Para evitar downloads desnecessários de conteúdo que ainda é recente, use o número de geração da cópia local como valor em uma pré-condição de não correspondência, que é incluída na solicitação de download:

  • Se os dados no seu bucket continuarem correspondendo à cópia local, os números de geração serão correspondentes. Isso causará falha na pré-condição. Como resultado, a solicitação geral falha com uma resposta 304 Not Modified e o download dos dados não é necessário.

  • Se os dados no seu bucket tiverem mudado, os números de geração não corresponderão e a condição prévia será bem-sucedida. Isso significa que a solicitação geral continua normalmente e faz o download da versão atualizada do conteúdo.

A seguir