Números de geração e condições prévias

Os números de geração de objeto permitem que os usuários identifiquem recursos de dados de maneira exclusiva e apliquem condições prévias para garantir a atomicidade das transações em várias etapas.

Gerações

Mesmo sem o Controle de versão do objeto ativado, todos os objetos do Cloud Storage têm números de geração e números de metageração. O número de geração é alterado sempre que o objeto é sobrescrito, e o número da metageração é alterado sempre que os metadados do objeto são atualizados.

Como os números de metageração de objeto são redefinidos para 1 para cada nova geração de objeto, eles são significativos apenas quando pareados com um número de geração.

Os intervalos também mantêm um número de metageração, que permite que os usuários identifiquem com exclusividade um estado de metadados do intervalo. Como os intervalos não têm dados de payload e, portanto, nenhum número de geração, os números de metageração são significativos por si só.

Exemplo: upload paralelo

Em uploads paralelos, você divide um objeto em várias partes, faz upload das partes em um local temporário simultaneamente e compose o objeto original dessas partes temporárias. Se um processo independente usar inadvertidamente o mesmo nome de uma ou mais das partes temporárias que você fez upload, quando você tentar compose o objeto, componentes incorretos serão usados ​​e o objeto será corrompido.

Usando números de geração, você evita que isso aconteça. Se você incluir o número de geração de cada parte carregada quando fizer sua solicitação de compose, a compose ocorrerá com as partes corretas ou a solicitação apresentará falha com uma resposta 404 Not Found.

Condições prévias

As condições prévias dizem ao Cloud Storage para executar uma solicitação somente se o número de geração ou metageração do objeto afetado atender aos critérios de condição prévia. Essas verificações dos números de geração e metageração garantem que o objeto esteja no estado esperado, permitindo que você execute atualizações seguras de leitura-modificação-gravação e operações condicionais em objetos.

Quando uma condição prévia de match usa um número específico de geração ou metageração, o objeto do Cloud Storage a que a solicitação se aplica precisa ter o mesmo número de geração/metageração. Em caso afirmativo, a solicitação é bem-sucedida. Se isso não ocorrer, a solicitação apresentará falha e uma resposta 412 Precondition Failed será retornada.

Quando uma condição prévia match usa o valor 0 em vez de um número de geração, a solicitação só será bem-sucedida se não houver objetos ativos no intervalo do Cloud Storage com o nome especificado na solicitação. Se houver tal objeto, a solicitação apresentará falha e uma resposta 412 Precondition Failed será retornada.

Condições prévias são frequentemente usadas em solicitações de alteração - uploads, exclusões, cópias ou atualizações de metadados - para evitar disputas. Disputas podem surgir quando a mesma solicitação é enviada repetidamente ou quando processos independentes interferem uns com os outros. Por exemplo, várias tentativas de solicitação após uma interrupção de rede ou usuários realizando uma operação de leitura-modificação-gravação no mesmo objeto podem criar disputas.

Além das condições prévias que usam números de geração e metageração, também há condições prévias disponíveis que usam ETags. As ETags da API XML para objetos não compostos mudam apenas quando o conteúdo é alterado, enquanto as ETags para objetos compostos e recursos da API JSON mudam sempre que o conteúdo ou os metadados são alterados. Para mais informações sobre ETags, consulte Hashes e ETags: práticas recomendadas.

Custo das condições prévias

As condições prévias têm um custo de desempenho e faturamento: para cada operação de mutação, você também emite uma solicitação de metadados GET faturável para determinar o número de geração/metageração do objeto. Como consideração de desempenho, condições prévias podem dobrar potencialmente a parte da rede da latência geral da operação adicionando uma viagem de ida e volta extra, que pode ser um fator importante em operações sensíveis à latência. Como uma consideração de preços, a solicitação de metadados GET que permite o uso de condições prévias é cobrada a uma taxa de US$ 0,004 por 10.000 operações.

Dependendo do seu aplicativo, há maneiras de evitar custos de desempenho e faturamento associados ao uso de condições prévias, como:

  • 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.
  • Usando um esquema de nomenclatura que evita mais de uma mutação do mesmo nome de objeto para que você não precise usar condições prévias.
  • Tendo conhecimento da aplicação de quais objetos foram criados recentemente, você já sabe quando usar a condição prévia if-generation-match:0.
  • Lembrando os resultados de chamadas GET realizadas antes de mutações.

Condições prévias na API XML

Na API XML, os números de geração e metageração são expostos pelos cabeçalhos de resposta x-goog-generation e x-goog-metageneration. Esses cabeçalhos são retornados na resposta de uma solicitação HEAD para um objeto.

Consulte a Referência de cabeçalhos HTTP para uma listagem completa dos cabeçalhos de solicitação de condição prévia que você pode usar para tornar a solicitação condicional ao estado do objeto solicitado. Por exemplo:

  • Use a condição prévia x-goog-if-generation-match para executar uma solicitação apenas se o número de geração na condição prévia corresponder ao número de geração do objeto solicitado. Se você usar 0 em vez de um número de geração, a solicitação só será bem-sucedida se não houver nenhum objeto ativo em seu intervalo correspondente ao objeto nomeado na solicitação.

  • Use as condições prévias x-goog-if-metageneration-match para executar uma solicitação apenas se o número de metageração no cabeçalho corresponder ao número de metageração do objeto solicitado.

  • Use a condição prévia If-Modified-Since com solicitações GET ou HEAD. Essas solicitações são executadas somente se o horário de criação da geração mais recente do objeto, ou seja, a última modificação do objeto, tiver ocorrido mais recentemente do que o horário especificado na condição prévia.

  • Use ETags e as condições prévias If-Match ou If-None-Match com solicitações GET ou HEAD. Essas solicitações são executadas somente se o objeto solicitado corresponder ou não ao ETag especificado na condição prévia.

  • Use várias condições prévias na mesma solicitação. Por exemplo, se você estiver usando x-goog-if-generation-match, também poderá usar x-goog-if-metageneration-match.

Condições prévias na API JSON

Na API JSON, é possível conseguir os números de geração e metageração por meio das propriedades generation e metageneration de uma resposta que contém um recurso de objeto ou de intervalo. Um recurso de objeto ou intervalo é retornado no corpo da resposta de uma solicitação GET para o objeto ou para o intervalo.

Para usar condições prévias em solicitações, inclua as condições prévias como parâmetros de consulta no final do URL. Para cada condição prévia adicione um parâmetro de consulta com o mesmo nome dela. Por exemplo, este é um exemplo de solicitação que usa ifGenerationMatch: https://www.googleapis.com/storage/v1/b/testgrid-triage-testing/o/test?ifGenerationMatch=1122334455

Nesse exemplo, a API só realiza essa solicitação se a geração do objeto for 1122334455.

A API JSON também aceita ETags HTTP 1.1 e os cabeçalhos HTTP If-Match e If-None-Match correspondentes para todos os recursos, incluindo intervalos, objetos e ACLs. Uma ETag é retornada como parte do cabeçalho de resposta sempre que um recurso é retornado, bem como incluída no próprio recurso.

Aqui estão alguns exemplos de condições prévias que você pode usar para tornar a solicitação condicional ao estado do objeto solicitado:

  • Use as condições prévias ifGenerationMatch e ifGenerationNotMatch para executar uma solicitação somente se o número de geração na propriedade coincidir ou não com o número de geração do objeto solicitado. Se você usar 0 em vez de um número de geração em ifGenerationMatch, a solicitação só será bem-sucedida se não houver nenhum objeto ativo em seu intervalo correspondente ao objeto nomeado na solicitação.

  • Use as condições prévias ifMetagenerationMatch e ifMetagenerationNotMatch para executar uma solicitação em um intervalo ou objeto. As solicitações serão bem-sucedidas somente se o número da metageração na propriedade corresponder ou não ao número da metageração do intervalo ou objeto solicitado.

  • Use ETags e as condições prévias If-Match ou If-None-Match como cabeçalhos nas solicitações. Essas solicitações são executadas somente se o objeto solicitado corresponder ou não ao ETag especificado na condição prévia.

  • Use várias condições prévias na mesma solicitação. Por exemplo, se você estiver usando ifGenerationMatch ao solicitar um objeto, também poderá usar ifMetagenerationMatch.

Observe que condições prévias de geração e metageração não são aceitas para operações de ACL. Em vez disso, use o recurso de entrada de controle de acesso ETag. Isso pode ser encontrado dentro de cada recurso de entrada de controle de acesso, que também pode ser acessado no objeto de contenção ou recurso do intervalo.

Exemplos de condições de corrida

Leitura-modificação-gravação simultânea

Um padrão comum para atualizar metadados de intervalo ou objeto envolve ler o estado atual, aplicar modificações localmente e enviar os metadados modificados de volta ao Cloud Storage para gravação. Isso pode ser precário se dois ou mais processos independentes tentarem a sequência simultaneamente.

Considere este caso: você quer adicionar uma entrada de ACL a um colaborador para que ele possa acessar seu intervalo. Ao mesmo tempo, uma colega de trabalho quer remover um colaborador separado que não precisa mais acessar o intervalo.

Para fazer isso, você e sua colega de trabalho leem o mesmo estado inicial para os metadados do intervalo e cada um faz a modificação que quiser nas entradas de ACL do intervalo. Quando você gravar suas modificações no Cloud Storage, os metadados serão atualizados corretamente. Infelizmente, suas alterações são perdidas assim que sua colega de trabalho faz o upload das modificações dela, já que não tinha como levar em consideração sua atualização. Como resultado, a entrada de ACL do seu colaborador é perdida. Ela não poderá acessar seu intervalo e ninguém está ciente do que aconteceu (sem voltar e ver as entradas de ACL).

Como evitar a disputa

Você e sua colega de trabalho podem evitar essa disputa adicionando uma condição prévia if-metageneration-match a cada uma das suas operações de gravação. Na condição prévia, você usa o número de metageração do intervalo, que faz parte dos metadados recebidos na operação de leitura inicial.

Quando suas modificações adicionam a entrada de ACL, o número de metageração do intervalo é alterado. Agora que as condições prévias estão sendo usadas, quando sua colega de trabalho tenta gravar uma versão das entradas de ACL, o número de metageração do intervalo não corresponde ao número na condição prévia e ela é informada da falha na atualização com um código de resposta 412 Precondition Failed. Ao receber esse código de resposta, sua colega de trabalho pode agir de acordo, executando um novo ciclo de leitura-modificação-gravação usando os metadados atualizados.

Várias tentativas de solicitação

O Cloud Storage é um sistema distribuído. Como as solicitações podem apresentar falha devido a condições de rede ou de serviço, o Google recomenda que você tente novamente com espera exponencial. No entanto, devido à natureza dos sistemas distribuídos, às vezes essas tentativas podem causar um comportamento inesperado.

Considere este caso: você quer excluir um arquivo, file.txt, armazenado no Cloud Storage. Depois disso, você quer adicionar um novo arquivo com o mesmo nome ao Cloud Storage.

Para realizar 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ê decide fazer o upload de um novo file.txt, e ele é bem-sucedido.

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 escutá-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, comece coletando os metadados para file.txt para determinar geração atual dele. Em seguida, envie a solicitação de exclusão com uma condição prévia if-generation-match que use o número de geraçã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 de exclusão chega ao Cloud Storage ou de quantas vezes a solicitação de exclusão com a condição prévia é enviada. Com a condição prévia if-generation-match, quaisquer tentativas não intencionais de alterar uma geração diferente de file.txt apresentarão falha 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 seguiu sua solicitação de exclusão, você pode evitar muitas delas com uma if-generation-match:0 aplicada à solicitação de upload. O uso dessa condição prévia garante que as novas tentativas do upload não sejam gravadas acidentalmente no objeto duas vezes, porque a condição prévia permite que a solicitação seja bem-sucedida apenas se não houver nenhuma geração atual do objeto.

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

Limitações de if-generation-match:0

if-generation-match:0 não pode impedir que a criação de objetos ocorra duas vezes se o primeiro objeto for excluído, porque a ausência do objeto não é exclusivamente identificável. Considere o caso a seguir, em que nenhum dado é perdido, mas você termina com um arquivo que não esperava:

  1. Você começa com uma solicitação GET para os metadados do file.txt para encontrar o número de geração. Na resposta, você descobre que file.txt não existe.

  2. Sabendo disso, você solicita o upload do file.txt com a condição prévia if-generation-match:0, mas a solicitação expira quando um roteador intermediário perde temporariamente a conectividade.

  3. Tendo falhado na primeira vez, você tenta mais uma vez sua solicitação de upload, novamente com a condição prévia if-generation-match:0. Desta vez, a solicitação é bem-sucedida.

  4. Logo depois, você envia uma solicitação para excluir o file.txt, que é bem-sucedida.

  5. Se o roteador que perdeu a conectividade se recuperar e enviar sua primeira solicitação de upload para o Cloud Storage, a condição prévia da solicitação ainda será uma correspondência. Por isso, o file.txt é recriado. Com ou sem a condição prévia, o file.txt inesperadamente faz o upload uma segunda vez.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Precisa de ajuda? Acesse nossa página de suporte.