Esta página aborda as condições prévias dos pedidos, que usa para impedir que os pedidos sejam aplicados a um recurso quando este se encontra num estado inesperado.
Introdução
Quando são usadas pré-condições num pedido ao Cloud Storage, o pedido só prossegue se o recurso segmentado cumprir os critérios definidos nas pré-condições. As verificações de pré-condições garantem que um contentor ou um objeto se encontra no estado esperado, o que lhe permite fazer atualizações de leitura-modificação-escrita seguras e operações condicionais.
As pré-condições são frequentemente usadas para evitar condições de concorrência em pedidos de mutação, como carregamentos, eliminações ou atualizações de metadados. As condições de corrida podem surgir quando o mesmo pedido é enviado repetidamente ou quando processos independentes tentam modificar o mesmo recurso. Consulte os exemplos de condições de concorrência e corrupção de dados para mais informações. As pré-condições também são frequentemente usadas quando se obtêm metadados de objetos e dados em pedidos sucessivos, para garantir que o objeto não foi alterado no período entre os dois pedidos.
Critérios de pré-condição
O Cloud Storage suporta a utilização de várias propriedades de recursos imutáveis diferentes em pré-condições:
- Números de geração e metageração
- ETags
- A data
Last-Modified
(disponível apenas quando obtém dados de objetos ou metadados através da API XML)
A tabela seguinte apresenta as pré-condições suportadas pela API JSON e pela API XML:
API JSON | API XML | Descrição |
---|---|---|
Parâmetro de consulta ifGenerationMatch |
Cabeçalho x-goog-if-generation-match |
O pedido prossegue se o generation do recurso de destino corresponder ao valor usado na pré-condição. Se os valores não corresponderem, o pedido falha com uma resposta 412 Precondition Failed . |
Parâmetro de consulta ifMetagenerationMatch |
Cabeçalho x-goog-if-metageneration-match |
O pedido prossegue se o metageneration do recurso de destino corresponder ao valor usado na pré-condição. Se os valores não corresponderem, o pedido falha com uma resposta 412 Precondition Failed . |
Parâmetro de consulta ifGenerationNotMatch |
N/A | O pedido prossegue se o generation do recurso de destino não corresponder ao valor usado na pré-condição. Se os valores corresponderem, o pedido falha com uma resposta 304 Not Modified . |
Parâmetro de consulta ifMetagenerationNotMatch |
N/A | O pedido prossegue se o metageneration do recurso de destino não corresponder ao valor usado na pré-condição. Se os valores corresponderem, o pedido falha com uma resposta 304 Not Modified . |
Cabeçalho If-Match |
Cabeçalho If-Match |
Aplicável a pedidos que obtêm dados. O pedido prossegue se o ETag do recurso de destino corresponder ao valor usado na pré-condição. Se os valores não corresponderem, o pedido falha com uma resposta 412 Precondition Failed . |
Cabeçalho If-None-Match |
Cabeçalho If-None-Match |
Aplicável a pedidos que obtêm dados. O pedido prossegue se o ETag do recurso de destino não corresponder ao valor usado na pré-condição. Se os valores corresponderem, o pedido falha com uma resposta 304 Not Modified . |
N/A | Cabeçalho If-Modified-Since |
O pedido prossegue se o recurso de destino tiver uma data Last-Modified posterior ao valor usado na condição prévia. Se o recurso de destino não cumprir esta pré-condição, o pedido falha com uma resposta 304 Not Modified . |
N/A | Cabeçalho If-Unmodified-Since |
O pedido prossegue se o recurso de destino tiver uma data Last-Modified anterior ou igual ao valor usado na pré-condição. Se o recurso de destino não cumprir esta pré-condição, o pedido falha com uma resposta 412 Precondition Failed . |
Pré-condições de composição de objetos
Quando realizar a composição de objetos, tanto a API JSON como a API XML suportam o seguinte:
As pré-condições generation-match e metageneration-match para o objeto de destino.
A pré-condição de correspondência de geração para cada objeto de origem. A utilização desta pré-condição impede a utilização de componentes incorretos no caso em que um processo independente substitui um dos componentes pretendidos da composição. Se usar pré-condições e ocorrer uma substituição deste tipo, as operações falham com uma resposta
412 Precondition Failed
.compose
Pré-condições de cópia de objetos
Quando copia ou reescreve um objeto no Cloud Storage, a API JSON e a API XML suportam a utilização de pré-condições padrão para o objeto de destino. Cada API tem suporte de pré-condições adicional para objetos de origem:
A API JSON suporta pré-condições de geração e metageração para o objeto de origem, que são especificadas através de parâmetros de consulta com o prefixo
ifSource
.Todas as pré-condições suportadas pela API XML podem ser usadas para o objeto de origem. Estas pré-condições são especificadas em cabeçalhos com o prefixo
x-goog-copy-source-
.
O valor 0
numa pré-condição de correspondência de geração
A pré-condição 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 num pedido,
o pedido só prossegue se não existir nenhum objeto com o nome especificado no
contentor ou se existirem apenas versões não atuais do objeto no contentor. Se existir uma versão em direto com o nome especificado, o pedido falha com um código de estado de 412 Precondition Failed
.
Práticas recomendadas e considerações
Pode usar várias pré-condições num único pedido. Se alguma das pré-condições não for cumprida, o pedido geral falha.
Os contentores não têm um número de geração, embora tenham um número de metageração. Não deve usar pré-condições que especifiquem um número de geração num pedido de contentor.
Se usar uma pré-condição de metageração num pedido de objeto, deve usar sempre também uma pré-condição de geração. Isto impede que o pedido seja bem-sucedido num objeto diferente que, coincidentemente, tenha um número de metageração que passe a pré-condição.
Para contentores que tenham versões de objetos atuais e não atuais, os pedidos 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 pedido. Isto significa que, para um pedido geral que use pré-condições, o pedido falha se a versão publicada não corresponder à pré-condição, independentemente de uma versão não atual corresponder ou não às pré-condições.
Geralmente, deve usar pré-condições de geração e metageração em vez de pré-condições de ETag. Em conjunto, os números de geração e metageração acompanham todas as atualizações de objetos, incluindo as alterações de metadados, oferecendo uma garantia mais forte do que as ETags. Além disso, os números de geração e metageração são consistentes nas APIs, ao passo que os ETags não o são.
Não é possível usar pré-condições em carregamentos multipartes da API XML. Se tentar fazê-lo, recebe um erro
400 NotImplemented
.
Custo das pré-condições
Muitas arquiteturas que usam pré-condições exigem que faça um pedido de metadados de objetos antes do pedido principal, para determinar o número de geração e/ou metageração atual:
- Um pedido adicional significa que pode duplicar a parte da rede da latência geral da operação adicionando uma viagem de ida e volta adicional, o que pode ser um fator importante em operações sensíveis à latência.
- Um pedido adicional incorre numa taxa de operação e, na maioria dos casos, numa taxa de rede.
Consoante a sua aplicação, existem formas de reduzir os impactos da utilização de pré-condições, como:
- Armazenar os números de geração e metageração dos seus objetos localmente para que já saiba os números corretos a usar na sua pré-condição.
- Ter conhecimento da aplicação sobre que objetos foram criados recentemente, para que já saiba quando usar a condição prévia
if-generation-match:0
.
Exemplo: usar uma pré-condição
O exemplo seguinte usa a pré-condição generation-match num pedido para carregar um objeto. Para que o pedido avance, tem de existir um objeto pré-existente armazenado no contentor com o nome especificado, e o número de geração do objeto pré-existente tem de corresponder ao número fornecido na pré-condição:
Linha de comandos
Use a flag --if-generation-match
juntamente com o comando normal:
gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME --if-generation-match=GENERATION
Onde:
GENERATION
é o número de geração pretendido do objeto que está a substituir. Por exemplo,1122334455667788
.OBJECT_LOCATION
é o caminho local para o seu objeto. Por exemplo,Desktop/dog.png
.DESTINATION_BUCKET_NAME
é o nome do contentor para o qual está a carregar o seu objeto. Por exemplo,my-bucket
.
API JSON
Ter a CLI gcloud instalada e inicializada, o que lhe permite gerar um token de acesso para o cabeçalho
Authorization
.Use
cURL
para chamar a API JSON com um pedido dePOST
objeto: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"
Onde:
OBJECT_LOCATION
é o caminho local para o seu 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 contentor para o qual está a carregar o seu objeto. Por exemplo,my-bucket
.OBJECT_NAME
é o nome que quer dar ao seu objeto. Por exemplo,dog.png
.GENERATION
é o número de geração pretendido do objeto que está a substituir. Por exemplo,1122334455667788
.
API XML
Ter a CLI gcloud instalada e inicializada, o que lhe permite gerar um token de acesso para o cabeçalho
Authorization
.Use
cURL
para chamar a API XML com um pedido dePUT
objeto: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"
Onde:
OBJECT_LOCATION
é o caminho local para o seu 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 está a substituir. Por exemplo,1122334455667788
.BUCKET_NAME
é o nome do contentor para o qual está a carregar o seu objeto. Por exemplo,my-bucket
.OBJECT_NAME
é o nome que quer dar ao seu objeto. Por exemplo,dog.png
.
Cenários de utilização de pré-condições
Os seguintes cenários exploram as condições de concorrência e os exemplos de colocação em cache que beneficiam da utilização de pré-condições.
Várias tentativas de pedidos
O Cloud Storage é um sistema distribuído. Uma vez que os pedidos podem falhar devido a condições de rede ou de serviço, a forma recomendada de repetir as falhas é com o recuo exponencial. No entanto, devido à natureza dos sistemas distribuídos, por vezes, estas novas tentativas podem causar um comportamento surpreendente.
Considere o seguinte caso: quer eliminar um objeto, file.txt
, armazenado num dos seus contentores. Posteriormente, quer adicionar um novo objeto com o mesmo nome ao contentor. Para o fazer, envia um pedido de eliminação para eliminar o objeto. No entanto, uma condição de rede, como um router intermédio que perde temporariamente a conetividade, impede que o pedido chegue ao Cloud Storage e não recebe uma resposta.
Como não recebeu uma resposta ao primeiro pedido, envia um segundo pedido de eliminação do objeto, que é bem-sucedido, e recebe uma resposta a confirmar a eliminação. Um minuto depois, carrega um novo file.txt
e o carregamento é bem-sucedido.
Surge uma condição de corrida se o router que perdeu a conetividade a recuperar posteriormente e enviar o seu pedido de eliminação original, aparentemente perdido, para o Cloud Storage. Quando o pedido chega ao Cloud Storage, tem êxito porque existe um novo file.txt
. O Cloud Storage envia uma resposta que não recebe porque o seu cliente deixou de a ouvir.
Não só o novo ficheiro é eliminado, ao contrário das suas intenções, como também não se apercebe de que a segunda eliminação ocorreu.
O diagrama seguinte mostra o que aconteceu:
Impedir a condição de corrida
Para evitar a situação acima, deve começar por obter os metadados de file.txt
para determinar a respetiva geração atual. Em seguida, use a geração numa condição prévia de correspondência de geração que inclui como parte do pedido de eliminação. A pré-condição garante que apenas o objeto com esse número de geração específico é eliminado, independentemente de quando o pedido de eliminação chega ao Cloud Storage ou de quantas vezes o pedido de eliminação com a pré-condição é enviado. Todas as tentativas não intencionais de eliminar uma geração diferente de file.txt
falham com o código de resposta 412 Precondition Failed
.
Uma vez que interrupções de rede semelhantes podem causar condições de concorrência para o pedido de carregamento que se seguiu ao pedido de eliminação, pode evitar muitas dessas condições de concorrência usando o valor 0
numa pré-condição de correspondência de geração incluída no pedido de carregamento. A utilização desta pré-condição garante que as novas tentativas do carregamento não escrevem acidentalmente o objeto duas vezes, porque a pré-condição permite que o pedido prossiga apenas se não existirem gerações atuais do objeto.
Com estas pré-condições implementadas, protege os seus dados contra a perda acidental quando executa os pedidos de eliminação e carregamento. Isto pode ser visto no seguinte diagrama:
Associação de metadados de objetos
Os dados e os metadados de um objeto são entidades separadas que, em conjunto, definem o objeto no Cloud Storage. Como existem separadamente, é possível que os dados do objeto mudem enquanto trabalha com os metadados do objeto.
Considere os seguintes casos:
Quer transferir os metadados e os dados de um objeto, que têm de ser obtidos do Cloud Storage em duas solicitações separadas. Pede primeiro os metadados do objeto, mas, antes de poder pedir os dados do objeto, um processo ou um utilizador independente substitui o objeto. O seu pedido de dados do objeto continua a ser bem-sucedido, mas agora tem os metadados do objeto antigo e os dados do novo objeto.
Quer atualizar os metadados de um objeto, por isso, obtém os metadados atuais do objeto para determinar o respetivo estado atual. Antes de poder enviar o pedido de atualização dos metadados com as modificações pretendidas, um processo ou um utilizador independente substitui o objeto. O seu pedido de alteração dos metadados do novo objeto continua a ser bem-sucedido, mas agora está associado a dados de objetos diferentes dos pretendidos.
Impedir a condição de corrida
Para evitar que estas situações ocorram, deve usar o número de geração
devolvido no pedido inicial de metadados do objeto e, em seguida, usar este
valor numa pré-condição de correspondência de geração no segundo pedido. Desta forma, garante que os metadados correspondem corretamente aos dados ou que o segundo pedido falha com um código de resposta 412 Precondition Failed
, o que lhe permite pedir os metadados corretos para o novo objeto.
Se tiver dúvidas de que os metadados do objeto possam mudar entre o primeiro e o segundo pedido, também pode copiar o número de metageração encontrado no pedido inicial e usá-lo numa pré-condição de correspondência de metageração no segundo pedido.
Atualidade do texto local
Nos casos em que tem uma cópia local de um objeto armazenado no Cloud Storage, muitas vezes, quer que a cópia local se mantenha atualizada com a cópia armazenada no seu contentor. No entanto, se o objeto armazenado no seu contentor não mudar, não quer perder tempo nem recursos a transferi-lo novamente, especialmente se o objeto for grande.
Para evitar transferências desnecessárias de conteúdo que ainda é recente, pode usar o número de geração da sua cópia local como o valor numa pré-condição generation-not-match, que inclui no seu pedido de transferência:
Se os dados no seu contentor continuarem a corresponder à sua cópia local, os números de geração correspondem, o que faz com que a pré-condição falhe. Como resultado, o pedido geral falha com uma resposta
304 Not Modified
e os dados não são transferidos desnecessariamente.Se os dados no seu contentor tiverem sido alterados, os números de geração não correspondem e a pré-condição é bem-sucedida. Isto significa que o pedido geral prossegue normalmente e transfere a versão atualizada do conteúdo.
O que se segue?
- Saiba mais sobre os números de geração e metageração.
- Obter metadados de um objeto, como o respetivo número de geração.
- Saiba mais sobre a consistência no Cloud Storage.
- Saiba mais acerca das operações condicionalmente idempotentes que devem usar pré-condições.