Configurar o comportamento de novas tentativas no AWS SDK for Java 2.x - AWS SDK for Java 2.x

Configurar o comportamento de novas tentativas no AWS SDK for Java 2.x

As chamadas para Serviços da AWS podem falhar ocasionalmente por motivos inesperados. Certos erros, como controle de utilização (taxa excedida) ou erros transitórios, podem ser bem-sucedidos se a chamada for repetida. O AWS SDK for Java 2.x tem um mecanismo integrado para detectar esses erros e fazer novas tentativas automaticamente da chamada que é ativada por padrão para todos os clientes.

Esta página descreve como isso funciona, como configurar os modos distintos e adaptar o comportamento de novas tentativas.

Estratégias de novas tentativas

Uma estratégia de nova tentativa é um mecanismo usado no SDK para implementar novas tentativas. Cada cliente do SDK tem uma estratégia de novas tentativas criada no momento da compilação que não pode ser modificada após a criação do cliente.

A estratégia de novas tentativas tem as seguintes responsabilidades.

  • Classificar as exceções como passíveis de novas tentativas ou não.

  • Calcular o atraso sugerido para esperar antes da próxima tentativa.

  • Manter um bucket de token que forneça um mecanismo para interromper novas tentativas quando uma grande porcentagem de solicitações falhar e as novas tentativas não forem bem-sucedidas.

nota

Antes do lançamento das estratégias de novas tentativas com a versão 2.26.0 do SDK, as políticas de novas tentativas forneciam o mecanismo de novas tentativas no SDK. A API da política de novas tentativas é composta pela classe principal RetryPolicy no pacote software.amazon.awssdk.core.retry, enquanto o pacote software.amazon.awssdk.retries contém os elementos da API da estratégia de novas tentativas.

A API de estratégia de novas tentativas foi introduzida como parte de um amplo esforço da AWS para unificar as interfaces e o comportamento dos principais componentes dos SDKs.

O SDK para Java 2.x tem três estratégias de novas tentativas integradas: padrão, legada e adaptável. Todas as três estratégias de novas tentativas são pré-configuradas para tentar novamente em um conjunto de exceções que podem ser repetidas. Exemplos de erros que podem ser repetidos são tempos limite de soquete, controle de utilização do lado do serviço, falhas de simultaneidade ou bloqueio positivo e erros transitórios de serviço.

Estratégia padrão de novas tentativas

A estratégia de novas tentativas padrão é a implementação RetryStrategy recomendada para casos de uso normais. Ao contrário de AdaptiveRetryStrategy, a estratégia padrão geralmente é útil em todos os casos de uso de novas tentativas.

Por padrão, a estratégia padrão de novas tentativas faz o seguinte.

  • Faz novas tentativas nas condições configuradas no momento da compilação. Você pode ajustá-la com StandardRetryStrategy.Builder#retryOnException.

  • Tenta novamente duas vezes para um total de três tentativas. Você pode ajustá-la com StandardRetryStrategy.Builder#maxAttempts(int).

  • Para exceções sem controle de utilização, é usada a estratégia de recuo BackoffStrategy#exponentialDelay, com um atraso básico de 100 milissegundos e um atraso máximo de 20 segundos. Você pode ajustá-la com StandardRetryStrategy.Builder#backoffStrategy.

  • Para exceções de controle de utilização, é usada a estratégia de recuo BackoffStrategy#exponentialDelay, com um atraso básico de 1 segundo e um atraso máximo de 20 segundos. Você pode ajustá-la com StandardRetryStrategy.Builder#throttlingBackoffStrategy.

  • Executa a interrupção do circuito (desativando novas tentativas) no caso de grandes falhas no downstream. A primeira tentativa é sempre executada, somente as novas tentativas são desativadas. Ajuste com StandardRetryStrategy.Builder#circuitBreakerEnabled.

Estratégia de novas tentativas legada

A estratégia de novas tentativas legada é RetryStrategy para casos de uso normais, no entanto, ela foi descontinuada para dar lugar a StandardRetryStrategy. Essa é a estratégia padrão de novas tentativas usada pelos clientes quando você não especifica outra estratégia.

Ela é caracterizada por tratar exceções de controle de utilização e que não são de controle de utilização de forma diferente. Para exceções de controle de utilização, o atraso base para o recuo é maior (500 ms) do que o atraso básico para exceções que não são de controle de utilização (100 ms), e as exceções de controle de utilização não afetam o estado do bucket de token.

A experiência de usar essa estratégia em grande escala dentro da AWS mostrou que ela não é particularmente melhor do que a estratégia de novas tentativas padrão. Além disso, ela falha em proteger os serviços downstream de novas tentativas e pode levar à falta de recursos no lado do cliente.

Por padrão, a estratégia de novas tentativas legada faz o seguinte.

  • Faz novas tentativas nas condições configuradas no momento da compilação. Você pode ajustá-la com LegacyRetryStrategy.Builder#retryOnException .

  • Tenta novamente três vezes para um total de quatro tentativas. Você pode ajustá-la com LegacyRetryStrategy.Builder#maxAttempts(int).

  • Para exceções sem controle de utilização, é usada a estratégia de recuo BackoffStrategy#exponentialDelay, com um atraso básico de 100 milissegundos e um atraso máximo de 20 segundos. Você pode ajustá-la com LegacyRetryStrategy.Builder#backoffStrategy.

  • Para exceções de controle de utilização, é usada a estratégia de recuo BackoffStrategy#exponentialDelay, com um atraso básico de 500 milissegundos e um atraso máximo de 20 segundos. Você pode ajustá-la com LegacyRetryStrategy.Builder#throttlingBackoffStrategy.

  • Executa a interrupção do circuito (desativando novas tentativas) no caso de grandes falhas no downstream. A interrupção do circuito nunca impede uma primeira tentativa bem-sucedida. Você pode ajustar esse comportamento com LegacyRetryStrategy.Builder#circuitBreakerEnabled.

  • O estado do disjuntor não é afetado pelas exceções de controle de utilização.

Estratégia de novas tentativas adaptável

A estratégia de novas tentativas adaptável é RetryStrategy para casos de uso com um alto nível de restrições de recursos.

A estratégia de novas tentativas adaptável inclui todos os recursos da estratégia padrão e adiciona um limitador de taxa do lado do cliente que mede a taxa de solicitações com controle de utilização em comparação com solicitações sem controle de utilização. A estratégia usa essa medida para reduzir a velocidade das solicitações na tentativa de permanecer em uma largura de banda segura, o que, idealmente, não causa erros de controle de utilização.

Por padrão, a estratégia de novas tentativas adaptável faz o seguinte.

  • Faz novas tentativas nas condições configuradas no momento da compilação. Você pode ajustá-la com AdaptiveRetryStrategy.Builder#retryOnException .

  • Tenta novamente duas vezes para um total de três tentativas. Você pode ajustá-la com AdaptiveRetryStrategy.Builder#maxAttempts(int).

  • Usa um atraso dinâmico de recuo baseado na carga atual em relação ao recurso de downstream.

  • Executa a interrupção do circuito (desativando novas tentativas) onde há um alto número de falhas no downstream. A interrupção do circuito pode impedir uma segunda tentativa em cenários de interrupção para proteger o serviço de downstream.

Atenção

A estratégia de novas tentativas adaptável pressupõe que o cliente trabalhe com um único recurso (por exemplo, uma tabela do DynamoDB ou um bucket do Amazon S3).

Se você usa um único cliente para vários recursos, o controle de utilização ou as interrupções associadas a um recurso resultam em maior latência e falhas quando o cliente acessa todos os outros recursos. Ao usar a estratégia de novas tentativas adaptável, recomendamos que você use um único cliente para cada recurso.

Também recomendamos que você use essa estratégia em situações em que todos os clientes usem a estratégia de novas tentativas adaptável em relação ao recurso.

Importante

O lançamento de estratégias de novas tentativas com a versão 2.26.0 do Java SDK inclui o novo valor de enumeração RetryMode.ADAPTIVE_V2. O modo ADAPTIVE_V2 corrige um erro que falhou em atrasar a primeira tentativa quando erros de controle de utilização foram detectados anteriormente.

Com a versão 2.26.0, os usuários obtêm automaticamente o comportamento do modo ADAPTIVE_V2 definindo o modo adaptive como uma variável de ambiente, propriedade do sistema ou configuração de perfil. Não há valor adaptive_v2 para essas configurações. Consulte a seção Especificar uma estratégia a seguir para saber como definir o modo.

Os usuários podem obter o comportamento anterior definindo o modo no código usando RetryMode.ADAPTIVE.

Resumo: comparação dos valores padrão da estratégia de novas tentativas

A tabela a seguir mostra os valores padrão das propriedades de cada estratégia de novas tentativas.

Estratégia Máximo de tentativas Atraso base para erros que não são de controle de utilização Atraso base para erros que são de controle de utilização Tamanho do bucket de tokens Custo do token por nova tentativa não relacionada ao controle de utilização Custo do token por nova tentativa relacionada ao controle de utilização
Padrão 3 100 ms 1000 ms 500 5 5
Legada 4 100 ms 500 ms 500 5 0
Adaptável 3 100 ms 100 ms 500 5 5
nota

Os clientes do DynamoDB usam uma contagem máxima de oito novas tentativas padrão para todas as estratégias, o que é maior do que os valores mostrados na tabela acima para outros clientes de AWS service (Serviço da AWS).

Especificar uma estratégia

Você tem quatro maneiras de especificar uma estratégia para o cliente de serviço.

No código

Ao criar um cliente, você pode configurar uma expressão do Lambda com uma estratégia de novas tentativas. O trecho a seguir configura uma estratégia de novas tentativas padrão que usa valores padrão em um cliente de serviço do DynamoDB.

DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy(RetryMode.STANDARD)) .build();

Você pode especificar RetryMode.LEGACY ou RetryMode.ADAPTIVE no lugar de RetryMode.STANDARD.

Como uma configuração de perfil

Incluir retry_mode como configuração de perfil no arquivo de configuração compartilhado da AWS. Especifique standard, legacy ou adaptive como um valor. Quando definido como uma configuração de perfil, todos os clientes de serviço criados enquanto o perfil está ativo usam a estratégia de novas tentativas especificada com valores padrão. É possível substituir essa configuração definindo uma estratégia de novas tentativas no código, conforme mostrado anteriormente.

Com o perfil a seguir, todos os clientes do serviço usam a estratégia de novas tentativas padrão.

[profile dev] region = us-east-2 retry_mode = standard

Como uma propriedade de sistema JVM

É possível configurar uma estratégia de novas tentativas para todos os clientes do serviço, a menos que seja substituída no código, usando a propriedade do sistema aws.retryMode. Especifique standard, legacy ou adaptive como um valor.

Use a opção -D ao invocar o Java, conforme mostrado no comando a seguir.

java -Daws.retryMode=standard ...

Você também pode definir a propriedade do sistema no código antes de criar qualquer cliente, conforme mostrado no trecho a seguir.

public void main(String[] args) { // Set the property BEFORE any AWS service clients are created. System.setProperty("aws.retryMode", "standard"); ... }

Com uma variável de ambiente

Você também pode usar a variável de ambiente AWS_RETRY_MODE com um valor de standardlegacy, ou adaptive. Assim como acontece com uma configuração de perfil ou propriedade do sistema JVM, a variável de ambiente configura todos os clientes de serviço com o modo de novas tentativas especificado, a menos que você configure um cliente no código.

O comando a seguir define o modo de novas tentativas standard para a sessão atual do shell.

export AWS_RETRY_MODE=standard

Personalizar uma estratégia

É possível personalizar qualquer estratégia de novas tentativas definindo o máximo de tentativas, a estratégia de recuo e as exceções que podem ser tentadas novamente. Você pode personalizar ao criar uma estratégia de novas tentativas ou ao criar um cliente usando um compilador de substituição que permite refinamentos adicionais da estratégia configurada.

Personalizar o máximo de tentativas

Configure o número máximo de tentativas durante a construção do cliente, conforme mostrado na declaração a seguir. A declaração a seguir personaliza a estratégia de novas tentativas padrão do cliente para um máximo de cinco tentativas, uma primeira tentativa e mais quatro.

DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy(b -> b.maxAttempts(5))) .build();

Você também pode criar a estratégia e fornecê-la ao cliente, conforme mostrado no exemplo de código a seguir. O código a seguir substitui o máximo padrão de 3 tentativas por 10 e configura um cliente do DynamoDB com a estratégia personalizada.

StandardRetryStrategy strategy = AwsRetryStrategy.standardRetryStrategy() .toBuilder() .maxAttempts(10) .build(); DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy(strategy)) .build();
Atenção

Recomendamos que você configure cada cliente com uma instância RetryStrategy exclusiva. Se uma instância RetryStrategy for compartilhada, falhas em um cliente poderão afetar o comportamento de novas tentativas no outro.

Você também pode definir o número máximo de tentativas para todos os clientes usando configurações externas em vez de código. Defina essa configuração conforme descrito na seção Especificar uma estratégia.

Personalizar exceções de novas tentativas

Você pode configurar exceções adicionais que acionam novas tentativas durante a construção do cliente. Essa personalização é fornecida para casos de borda em que são lançadas exceções que não estão incluídas no conjunto padrão de exceções que podem ser repetidas.

Os métodos retryOnException e retryOnExceptionOrCause adicionam novos tipos de exceção ao conjunto existente de exceções em que é possível fazer novas tentativas; eles não substituem o conjunto padrão. Isso permite que você estenda o comportamento de novas tentativas enquanto mantém os recursos de novas tentativas padrão do SDK.

O método retryOnExceptionOrCause adiciona uma exceção que pode ser repetida se o SDK lançar a exceção direta ou se a exceção for encapsulada como causa em outra exceção.

O trecho de código a seguir mostra os métodos que você usa para personalizar as exceções de novas tentativas: retryOnException e retryOnExceptionOrCause. O método retryOnExceptionOrCause adiciona uma exceção que pode ser repetida se o SDK lançar a exceção direta ou se a exceção for encapsulada.

DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy( b -> b.retryOnException(EdgeCaseException.class) .retryOnExceptionOrCause(WrappedEdgeCaseException.class))) .build();
Importante

As novas tentativas são desativadas para o cliente assíncrono Kinesis quando você chama um método subscribeToShard, independentemente da configuração da estratégia de novas tentativas.

Personalizar a estratégia de recuo

É possível criar a estratégia de recuo e fornecê-la ao cliente.

O código a seguir cria uma BackoffStrategy que substitui a estratégia de atraso exponencial padrão da estratégia padrão.

BackoffStrategy backoffStrategy = BackoffStrategy.exponentialDelay(Duration.ofMillis(150), // The base delay. Duration.ofSeconds(15)); // The maximum delay. DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy( b -> b.backoffStrategy(backoffStrategy))) .build();

Migração do RetryPolicy para o RetryStrategy

RetryPolicy (a API de política de novas tentativas) será compatível em um futuro próximo. Se você atualmente usa uma instância de RetryPolicy para configurar o cliente, tudo vai funcionar como antes. Nos bastidores, o Java SDK o adapta a uma RetryStrategy. As novas interfaces de estratégia de novas tentativas fornecem a mesma funcionalidade de uma RetryPolicy, mas são criadas e configuradas de forma diferente.