Repetir estratégia

Nesta página, descrevemos estratégias de repetição, como a espera exponencial truncada para solicitações com falha para o Cloud Storage.

Visão geral

Muitas ferramentas do Cloud Storage, como o Console do Cloud e a maioria das bibliotecas de cliente, usam automaticamente uma estratégia de repetição. Dessa forma, você normalmente não precisa implementar a sua própria. Se você implementar sua própria estratégia de repetição, considere o tipo de solicitação e a idempotência dela, que determina se a solicitação é segura para tentar novamente. Para solicitações seguras, é recomendável usar a espera exponencial truncada. As seguintes solicitações são repetidas:

  • Todas as solicitações ao Cloud Storage que retornam códigos de resposta HTTP 5xx, incluindo uploads e downloads de dados ou metadados.

  • Solicitações para o Cloud Storage que retornam um código de resposta HTTP 408.

  • Solicitações para o Cloud Storage que retornam um código de resposta HTTP 429, exceto aquelas que fazem upload de dados usando uploads retomáveis.

  • Tempos limite de soquete e desconexões TCP.

Para mais informações, consulte os códigos de status e erro do JSON e XML.

Algoritmo de espera exponencial

A espera exponencial truncada é uma estratégia padrão de resolução de erros para aplicativos de rede em que um cliente repete periodicamente uma solicitação com falha, aumentando o atraso entre as solicitações.

Um algoritmo de retirada exponencial repete solicitações exponencialmente, aumentando o tempo de espera entre novas tentativas até um tempo máximo de retirada. Veja o exemplo a seguir:

  1. Faça uma solicitação ao Cloud Storage.

  2. Se a solicitação falhar, aguarde 1 + random_number_milliseconds segundos e repita a solicitação.

  3. Se a solicitação falhar, aguarde 2 + random_number_milliseconds segundos e repita a solicitação.

  4. Se a solicitação falhar, aguarde 4 + random_number_milliseconds segundos e repita a solicitação.

  5. E assim por diante, até um tempo maximum_backoff.

  6. Continue aguardando e repetindo até uma quantidade máxima de tempo (deadline), mas não aumente o período de espera de maximum_backoff entre as repetições.

onde:

  • O tempo de espera é min(((2n)+random_number_milliseconds), maximum_backoff), com n incrementado em 1 para cada iteração (solicitação).

  • random_number_milliseconds é um número aleatório de milissegundos menor ou igual a 1.000. Isso ajuda a evitar casos em que muitos clientes são sincronizados e ficam repetindo ao mesmo tempo, enviando solicitações em ondas sincronizadas. O valor de random_number_milliseconds é recalculado após cada nova tentativa de solicitação.

  • maximum_backoff costuma ser 32 ou 64 segundos. O valor adequado depende do caso de uso.

É possível continuar repetindo depois de atingir o tempo maximum_backoff, mas recomendamos que sua solicitação falhe após um período de tempo para evitar que o aplicativo deixe de responder. Por exemplo, se um cliente usar um tempo maximum_backoff de 64 segundos, depois de atingir esse valor, o cliente poderá repetir a cada 64 segundos. Depois, o cliente para de repetir novamente após um deadline de 600 segundos.

O caso de uso e as condições da rede determinam quanto tempo os clientes precisam aguardar entre novas tentativas e quantas vezes eles podem tentar novamente. Por exemplo, clientes móveis de um aplicativo podem precisar fazer mais novas tentativas e por intervalos maiores quando comparados a clientes desktop do mesmo aplicativo.

Caso as solicitações de nova tentativa falhem após exceder o maximum_backoff e qualquer tempo extra permitido para novas tentativas, faça um relatório ou registre o erro usando um dos métodos listados em Suporte e ajuda.

Idempotência

Para determinar se é seguro repetir uma solicitação com falha para o Cloud Storage, considere se ela éidempotente, o que significa que aplicar a mesma operação várias vezes tem o mesmo efeito no estado do recurso de destino. As operações de idempotência geralmente são seguras para repetição.

Veja a seguir exemplos de condições que satisfazem a idempotência:

  • A operação tem o mesmo efeito observável no recurso de destino, mesmo quando solicitada continuamente.

  • A operação só funciona uma vez.

  • A operação não tem efeito observável no estado do recurso de destino.

Por exemplo, uma solicitação para listar buckets tem o mesmo efeito mesmo que a solicitação seja enviada várias vezes. Por outro lado, uma operação como criar uma nova notificação do Pub/Sub não é idempotente, porque ela cria um novo ID de notificação sempre que a solicitação é enviada.

Idempotência condicional

Um subconjunto de solicitações é idempotente condicionalmente, o que significa que elas só serão idempotentes se incluírem argumentos opcionais específicos. As operações que são condicionalmente seguras para repetição só precisam ser repetidas por padrão se o caso de condição for transmitido. O Cloud Storage aceita condições prévias e ETags como casos de condição para solicitações.

Repetir estratégia por ferramenta do Cloud Storage

Clique nas guias abaixo para ver as recomendações de estratégia de repetição para cada ferramenta do Cloud Storage.

Console

O Console do Cloud envia solicitações ao Cloud Storage em seu nome e processa qualquer espera necessária.

gsutil

O gsutil repete os erros listados na seção Visão geral sem exigir que você tome outras medidas. Pode ser necessário tomar medidas em relação a outros erros, como:

  • Credenciais inválidas ou permissões insuficientes.

  • Rede inacessível devido a um problema de configuração de proxy.

  • Operações individuais que falham em um comando em que você usa a sinalização de nível superior -m.

Para erros repetíveis, o gsutil repete solicitações usando uma estratégia de espera exponencial binária truncada: Assim, por padrão, o gsutil tentará novamente 23 vezes mais de 1+2+4+8+16+32+60... segundos por cerca de 10 minutos.

  • Se uma solicitação falhar, aguarde um período aleatório entre [0..1] segundos e tente novamente.
  • Se a solicitação falhar novamente, aguarde um período aleatório entre [0..2] segundos e tente novamente.
  • Se a solicitação falhar novamente, aguarde um período aleatório entre [0..4] segundos e tente novamente.
  • E assim por diante, até 23 novas tentativas, com cada período de repetição limitado por um máximo padrão de 60 segundos.

É possível configurar o número de tentativas e o atraso máximo de qualquer tentativa individual editando as variáveis de configuração num_retries e max_retry_delay na seção "[Boto]" do arquivo de configuração .boto.

Para transferências de dados usando os comandos cp e rsync do gsutil, a ferramenta fornece funcionalidade de nova tentativa na forma de transferências recuperáveis.

Bibliotecas de cliente

C++

Por padrão, a biblioteca de cliente do C++ usa espera exponencial.

C#

Por padrão, a biblioteca de cliente do C# usa espera exponencial.

Go

Por padrão, a biblioteca de cliente do Go usa a espera exponencial.

Java

Por padrão, a biblioteca de cliente do Java usa a espera exponencial.

Node.js

A biblioteca de cliente Node.js pode usar automaticamente as estratégias de espera para repetir solicitações com o parâmetro autoRetry.

PHP

Por padrão, a biblioteca de cliente do PHP usa espera exponencial.

Python

Por padrão, as operações aceitam novas tentativas para os seguintes códigos de erro:

  • Erros de conexão:
    • requests.exceptions.ConnectionError
    • requests.exceptions.ChunkedEncodingError (somente para operações que buscam ou enviam dados de payload para objetos, como uploads e downloads)
  • Códigos HTTP:
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
    • 508 Resource Limit Exceeded

As operações pelo Python usam as seguintes configurações padrão de espera exponencial:

Configuração Valor padrão (em segundos)
Tempo de espera inicial 1
Multiplicador do tempo de espera por iteração 2
Tempo máximo de espera 60
Prazo padrão 120

Um subconjunto de operações só será idempotente se incluir argumentos opcionais específicos. As operações que são condicionalmente seguras para repetição são repetidas por padrão se o caso de condição for transmitido. Atualmente, essas condições incluem:

  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED

    • É seguro repetir se generation ou if_generation_match tiver sido transmitido como um argumento para o método. Muitas vezes, os métodos aceitam apenas um desses dois parâmetros.
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED

    • É seguro repetir se if_metageneration_match tiver sido transmitido como um argumento para o método.
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

    • É seguro repetir se o método inserir uma etag no corpo da solicitação JSON. Para HMACKeyMetadata.update(), isso significa que a etag precisa ser configurada no próprio objeto HMACKeyMetadata. Para o método set_iam_policy() em outras classes, isso significa que a etag precisa ser configurada no argumento "política" transmitido para o método.

Políticas de repetição

As operações que são seguras ou condicionalmente seguras para repetição têm um parâmetro retry adicionado à assinatura do método. O padrão para esses parâmetros é um dos seguintes:

  • DEFAULT_RETRY
  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

Para modificar o comportamento padrão de repetição, crie uma cópia do objeto google.cloud.storage.retry.DEFAULT_RETRY chamando-o com um método with_XXX. with_predicate não é compatível com operações que buscam ou enviam dados de payload para objetos, como uploads e downloads. Recomendamos que você modifique os atributos um por um. Para mais informações, consulte a referência Repetir google-api-core.

Para configurar sua própria repetição condicional, crie um objeto ConditionalRetryPolicy e una o objeto personalizado Retry com DEFAULT_RETRY_IF_GENERATION_SPECIFIED, DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED ou DEFAULT_RETRY_IF_ETAG_IN_JSON.

Veja a seguir exemplos de novas repetições personalizadas:

  • blob.reload() usa DEFAULT_RETRY por padrão. Para modificar isso para que a função não seja repetida, chame-a como blob.reload(retry=None).

  • bucket.update() usa DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED por padrão. Para modificar isso para que a função repita novamente mesmo que o número de metageração não esteja especificado, chame-a como:

    from google.cloud.storage.retry import DEFAULT_RETRY
    bucket.update(retry=DEFAULT_RETRY)
  • bucket.list_blobs() usa DEFAULT_RETRY por padrão. Para modificar isso para que a chamada de API repita com um prazo de 20 segundos em vez dos 120 segundos padrão, chame-a como:

    from google.cloud.storage.retry import DEFAULT_RETRY
    modified_retry = DEFAULT_RETRY.with_deadline(20)
    bucket.list_blobs(retry=modified_retry)

Ruby

Por padrão, a biblioteca de cliente do Ruby usa espera exponencial.

APIs REST

Ao chamar a API JSON ou XML diretamente, use o algoritmo de espera exponencial para implementar sua própria estratégia de repetição.

Idempotência das operações

A tabela a seguir lista as operações do Cloud Storage que se enquadram em cada categoria de idempotência.

Idempotência Operações
Sempre idempotente
  • Todas as solicitações de recebimento e listagem
  • Inserir ou excluir buckets
  • Testar políticas e permissões de IAM do bucket
  • Bloquear políticas de retenção
  • Excluir uma chave HMAC ou notificação do Pub/Sub
Condicionalmente idempotente
  • Solicitações de atualização/patch para buckets com IfMetagenerationMatch ou ETag como condição prévia HTTP
  • Solicitações de atualização/patch para objetos com IfMetagenerationMatch ou ETag como condição prévia HTTP
  • Definir uma política de IAM do bucket com a ETag como condição prévia HTTP ou no corpo do recurso
  • Atualizar uma chave HMAC com ETag como condição prévia HTTP ou no corpo do recurso
  • Inserir, copiar, compor ou regravar objetos com ifGenerationMatch
  • Excluir um objeto com ifGenerationMatch (ou com um número de geração para versões de objeto)
Nunca idempotente
  • Criar uma chave HMAC
  • Criar uma notificação do Pub/Sub
  • Criar, excluir ou enviar solicitações de patch/atualização para ACLs de bucket e de objeto ou ACLs de objeto padrão

A seguir