As bibliotecas de cliente do Cloud para Java usam novas tentativas para lidar com falhas inesperadas e temporárias (ou seja, o servidor está temporariamente indisponível). Várias tentativas podem resultar em uma resposta bem-sucedida do servidor.
Os valores padrão de novas tentativas são selecionados pela equipe que opera o serviço de nuvem. Esses valores são configurados por RPC. Um serviço pode optar por ativar novas tentativas apenas para um subconjunto de RPCs. É possível que cada RPC de um serviço seja configurada de maneira diferente.
Parâmetros de tentativa
As bibliotecas de cliente têm dois tipos de parâmetros de nova tentativa para configurar:
- Código de status de nova tentativa:conjunto de códigos de status para tentar novamente.
- Tempo limite de nova tentativa ou limites de tentativa: RetrySettings configuráveis para definir os limites.
Localização da configuração padrão de nova tentativa de RPC
As configurações padrão de nova tentativa são definidas no arquivo {Client}StubSettings gerado. Usando a RPC ExportAssets no Java-Asset v3.64.0 como exemplo, as configurações padrão de nova tentativa são definidas nos seguintes locais:
Códigos de status de nova tentativa:configurados no arquivo
AssetServiceStubSettings.java. Exemplo:ImmutableMap.Builder<String, ImmutableSet<StatusCode.Code>> definitions = ImmutableMap.builder(); definitions.put("no_retry_0_codes", ImmutableSet.copyOf(Lists.<StatusCode.Code>newArrayList())); // ... More StatusCode configurations RETRYABLE_CODE_DEFINITIONS = definitions.build();Parâmetros de nova tentativa:configurados no arquivo
AssetServiceStubSettings.java. Exemplo:ImmutableMap.Builder<String, RetrySettings> definitions = ImmutableMap.builder(); RetrySettings settings = null; settings = RetrySettings.newBuilder() .setInitialRpcTimeoutDuration(Duration.ofMillis(60000L)) .setRpcTimeoutMultiplier(1.0) .setMaxRpcTimeoutDuration(Duration.ofMillis(60000L)) .setTotalTimeoutDuration(Duration.ofMillis(60000L)) .build(); definitions.put("no_retry_0_params", settings); // ... More RetrySettings configurations RETRY_PARAM_DEFINITIONS = definitions.build();
As duas configurações são mapeadas para a RPC no arquivo AssetServiceStubSettings.java. Exemplo:
builder
.exportAssetsSettings()
.setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes"))
.setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params"));
Conceitos de nova tentativa da biblioteca de cliente
A ativação de novas tentativas permite que uma RPC faça várias tentativas para tentar e realizar uma chamada bem-sucedida. Uma chamada bem-sucedida é uma resposta de um servidor que retorna um código de status OK (do gRPC) ou um código de status 2xx (de HttpJson).
Tentativa x operação
A configuração RetrySettings a seguir modifica as configurações de nova tentativa para a tentativa e a operação de uma RPC:
settings =
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(100L))
.setRetryDelayMultiplier(1.3)
.setMaxRetryDelayDuration(Duration.ofMillis(60000L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(60000L))
.setRpcTimeoutMultiplier(1.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(60000L))
.setTotalTimeoutDuration(Duration.ofMillis(60000L))
.build();
Uma tentativa de RPC é a tentativa individual feita, e uma operação de RPC é um conjunto de todas as tentativas feitas. Uma única invocação de RPC terá uma ou mais tentativas em uma única operação.
Os limites de RPC individuais (uma tentativa) são controlados pelas seguintes configurações:
setInitialRetryDelayDuration: atraso antes da primeira tentativa.setRetryDelayMultiplier: multiplicador de atraso aplicado entre cada tentativa.setMaxRetryDelayDuration: atraso máximo possível para uma tentativa.setInitialRpcTimeoutDuration: tempo limite para a primeira tentativa.setRpcTimeoutMultiplier: multiplicador de tempo limite aplicado entre cada tentativa.setMaxRpcTimeoutDuration: tempo limite máximo possível para uma tentativa.
Os limites totais de RPC (uma operação) são controlados pelas seguintes configurações:
setTotalTimeoutDuration: Tempo limite total permitido para toda a operação.setMaxAttempts: número máximo de tentativas permitidas.
Quando uma RPC é repetida
Uma RPC será repetida quando os dois cenários a seguir ocorrerem:
- Um código de status não bem-sucedido é recebido pela biblioteca, e o código de status é marcado como podendo ser tentado novamente.
- Uma invocação de RPC excede os limites de RPC individuais, mas ainda está dentro dos limites totais de RPC.
Se apenas um cenário for verdadeiro ou se nenhum deles for verdadeiro, a RPC não será repetida.
Por exemplo, se o tempo limite total não tiver sido excedido, mas a tentativa mais recente receber um código de status que não pode ser repetido.
Além disso, ao configurar os limites de RPC, é possível configurar os limites de cada tentativa, bem como os limites totais da RPC. O algoritmo de nova tentativa garante que os limites de uma tentativa individual estejam dentro dos limites totais da RPC.
Espera exponencial
A espera exponencial vai repetir as solicitações com um atraso crescente entre cada tentativa. Esse valor de atraso de nova tentativa pode ser limitado com um valor máximo de atraso de nova tentativa.
Por exemplo, as seguintes configurações de nova tentativa podem resultar nos seguintes tempos de atraso:
Initial Retry Delay: 100ms
Retry Delay Multiplier: 2.0
Max Retry Delay: 500ms
- Tentativa 1: atraso de 100 ms
- Tentativa 2: atraso de 200 ms
- Tentativa 3: atraso de 400 ms
- Tentativa 4: atraso de 500 ms
- …
- Tentativa X: atraso de 500 ms
Instabilidade
A instabilidade é uma variação adicionada usando aleatoriedade para distribuir quando as RPCs são invocadas. Cloud de Confiance by S3NS As bibliotecas de cliente sempre ativam a instabilidade para novas tentativas. Isso ajuda a distribuir as tentativas sem sobrecarregar o servidor.
O valor aleatório de instabilidade é calculado com base no atraso de nova tentativa. Antes de cada tentativa, o algoritmo de nova tentativa calcula um valor aleatório entre [1, RETRY_DELAY]. Esse valor calculado é o atraso aproximado antes que a solicitação seja enviada ao servidor.
As seguintes configurações de nova tentativa utilizam instabilidade e espera exponencial.
Initial Retry Delay: 100ms
Retry Delay Multiplier: 2.0
Max Retry Delay: 500ms
Isso pode resultar nos seguintes tempos de atraso:
- Tentativa 1: atraso de um valor aleatório entre
[1, 100]ms - Tentativa 2: atraso de um valor aleatório entre
[1, 200]ms - Tentativa 3: atraso de um valor aleatório entre
[1, 400]ms - Tentativa 4: atraso de um valor aleatório entre
[1, 500]ms - …
- Tentativa X: atraso de um valor aleatório entre
[1, 500]ms
Exemplos de nova tentativa
Os exemplos a seguir mostram o comportamento de algumas configurações de nova tentativa.
Não há novas tentativas
Este exemplo desativa as novas tentativas.
RetrySettings defaultNoRetrySettings =
RetrySettings.newBuilder()
// Use the default configurations for other settings
.setTotalTimeoutDuration(Duration.ofMillis(5000L))
// Explicitly set retries as disabled (maxAttempts == 1)
.setMaxAttempts(1)
.build();
Como alternativa, esse comportamento pode ser configurado com este exemplo:
RetrySettings defaultNoRetrySettings =
RetrySettings.newBuilder()
.setLogicalTimeoutDuration(Duration.ofMillis(5000L))
.build();
A tabela a seguir mostra as tentativas:
| Número da tentativa | Tempo limite da RPC | Atraso da nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 5.000 ms | 0ms | 0ms | 5.000 ms |
Exemplo de nova tentativa
Este exemplo ativa novas tentativas com atrasos e tempos limite especificados.
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(200L))
.setRetryDelayMultiplier(2.0)
.setMaxRetryDelayDuration(Duration.ofMillis(500L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(1500L))
.setRpcTimeoutMultiplier(2.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(3000L))
.setTotalTimeoutDuration(Duration.ofMillis(5000L))
.build();
A tabela a seguir mostra as tentativas:
| Número da tentativa | Tempo limite da RPC | Atraso da nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 1.500 ms | 0ms | 0ms | 1.500 ms |
| 2 (nova tentativa) | 3.000 ms | 200ms | 1.700 ms | 4.700 ms |
| 3 (nova tentativa não tentada) | - | 400ms | - | - |
Exemplo de nova tentativa: tempo limite total mais longo
Este exemplo é semelhante ao primeiro exemplo de nova tentativa, mas tem um tempo limite total mais longo para mostrar uma tentativa adicional e o tempo limite de RPC limitado para a última tentativa.
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(200L))
.setRetryDelayMultiplier(2.0)
.setMaxRetryDelayDuration(Duration.ofMillis(500L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(1500L))
.setRpcTimeoutMultiplier(2.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(3000L))
.setTotalTimeoutDuration(Duration.ofMillis(10000L))
.build();
A tabela a seguir mostra as tentativas:
| Número da tentativa | Tempo limite da RPC | Atraso da nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 1.500 ms | 0ms | 0ms | 1.500 ms |
| 2 (nova tentativa) | 3.000 ms | 200ms | 1.700 ms | 4.700 ms |
| 3 (nova tentativa) | 4.900 ms | 400ms | 5.100 ms | 10.000 ms |
O terceiro valor de tempo limite de RPC de nova tentativa é limitado devido ao valor de tempo limite total. Usar o multiplicador (2,0) com o valor de tempo limite anterior (3.000 ms) resulta em um tempo limite de RPC de 6.000 ms. No entanto, o tempo limite de RPC não deve exceder o tempo limite total e é reduzido para ser o "tempo restante" (10.000 - 5.100 = 4.900).
Exemplo de nova tentativa: tempo limite de RPC limitado
RetrySettings defaultRetrySettings =
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(200L))
.setRetryDelayMultiplier(2.0)
.setMaxRetryDelayDuration(Duration.ofMillis(500L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(500L))
.setRpcTimeoutMultiplier(2.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(2000L))
.setTotalTimeoutDuration(Duration.ofMillis(4000L))
.build();
A tabela a seguir mostra as tentativas:
| Número da tentativa | Tempo limite da RPC | Atraso da nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 500ms | 0ms | 0ms | 500ms |
| 2 (nova tentativa) | 1.000 ms | 200ms | 700ms | 1.700 ms |
| 3 (nova tentativa) | 1.900 ms | 400ms | 2.100 ms | 4.000 ms |
Outro exemplo em que o tempo limite de RPC é limitado para não exceder o tempo limite total.
Como configurar parâmetros de nova tentativa personalizados para uma RPC
O exemplo a seguir usa a biblioteca de cliente Java-Asset:
Crie a classe
RetrySettingscom suas configurações personalizadas:RetrySettings customRetrySettings = RetrySettings.newBuilder() // ... Retry Configurations .build(); RetrySettings customRetrySettings2 = RetrySettings.newBuilder() // ... Retry Configurations .build();Crie o
StubSettings.Builderpara seu cliente e configure-o para a RPC:AssetServiceStubSettings.Builder assetStubSettingsBuilder = AssetServiceStubSettings.newBuilder(); assetStubSettingsBuilder .exportAssetsSettings() // Set your custom Retry Settings .setRetrySettings(customRetrySettings) // Set your custom Retryable Codes .setRetryableCodes(ImmutableSet.of(StatusCode.Code.DEADLINE_EXCEEDED));O snippet de código fornecido está definindo configurações de nova tentativa personalizadas para a RPC
ExportAssetsdoAssetServiceClient. Ele configura a RPCExportAssetspara usar as configurações de nova tentativa configuradas emcustomRetrySettingse define os códigos que podem ser repetidos comoDEADLINE_EXCEEDED.Crie as configurações para o cliente como
assetSettings:AssetServiceSettings assetSettings = AssetServiceSettings.create(assetStubSettingsBuilder.build());Crie o cliente com as configurações como
assetClient.try (AssetServiceClient assetClient = AssetServiceClient.create(assetSettings)) { ... }
Repita a etapa 2 para cada RPC que você quiser configurar. Exemplo:
AssetServiceStubSettings.Builder assetStubSettingsBuilder = AssetServiceStubSettings.newBuilder();
// Modify the retry params for ExportAssets RPC
assetStubSettingsBuilder
.exportAssetsSettings()
.setRetrySettings(customRetrySettings)
.setRetryableCodes(ImmutableSet.of(StatusCode.Code.DEADLINE_EXCEEDED));
// Modify the retry params for ListAssets RPC
assetStubSettingsBuilder
.listAssetsSettings()
.setRetrySettings(customRetrySettings2)
.setRetryableCodes(ImmutableSet.of(StatusCode.Code.UNAVAILABLE));
Perguntas frequentes
A seguir, apresentamos perguntas frequentes sobre o comportamento de nova tentativa do cliente.
Eu esperava X tentativas, mas foram feitas Y tentativas.
A menos que você especifique explicitamente o número máximo de tentativas (junto com a desativação das configurações de tempo limite), talvez não veja consistentemente o mesmo número de tentativas. Os valores aleatórios de instabilidade para o atraso de RPC dificultam a previsão de quando a solicitação é enviada.
A RPC retornou uma falha antes que o valor de tempo limite total fosse atingido.
O algoritmo de nova tentativa calcula o valor de atraso de nova tentativa com instabilidade durante cada tentativa. O atraso de nova tentativa calculado será programado para ser executado no futuro (ou seja, currentTime() + jitteredRetryDelay). Se o tempo de tentativa programado exceder o tempo limite total, a tentativa final não será feita.
Configurei configurações personalizadas e estou tendo problemas de cota.
Talvez você tenha configurado RetrySettings para ser executado de forma muito agressiva. Os valores padrão de nova tentativa são escolhidos pela equipe que opera o serviço.
Considere aumentar o atraso de nova tentativa (atraso inicial de nova tentativa e multiplicador de nova tentativa) para que as tentativas sejam espaçadas e menos frequentes. Isso pode resultar em uma resposta mais lenta.
Seu caso de uso pode exigir uma resposta mais rápida ou tentativas mais frequentes, ou ambos. Nesse caso, tente aumentar os limites de cota.