As bibliotecas de cliente do Cloud para Java usam novas tentativas para lidar com falhas inesperadas e temporárias (ou seja, o servidor está indisponível temporariamente). 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 de nova tentativa 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 configurado de maneira diferente.
parâmetros de tentativa
As bibliotecas de cliente têm dois tipos de parâmetros de repetição 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.
Local padrão da configuração de nova tentativa de RPC
As configurações de nova tentativa padrão são definidas no arquivo
{Client}StubSettings gerado. Usando a RPC ExportAssets em
Java-Asset v3.64.0 como exemplo, as configurações de nova tentativa padrão 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 repetição: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 novas tentativas da biblioteca de cliente
Ao ativar as novas tentativas, uma RPC pode fazer várias tentativas para 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 2xx (do HttpJson).
Tentativa x operação
A configuração RetrySettings a seguir modifica as configurações de nova tentativa para uma tentativa e uma operação de 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. 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:
setTotalTimeout:o 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 sem sucesso é recebido pela biblioteca, e o código de status é marcado como "pode ser tentado novamente".
- Uma invocação de RPC excede os limites individuais, mas ainda está dentro dos limites totais.
Se apenas um cenário for verdadeiro ou se nenhum deles for, a RPC não será repetida.
Por exemplo, se o tempo limite total não tiver sido excedido, mas a última tentativa 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 para cada tentativa e os limites totais de RPC. O algoritmo de nova tentativa garante que os limites de uma tentativa individual estejam dentro dos limites totais do RPC.
Espera exponencial
A espera exponencial repete as solicitações com um atraso cada vez maior entre cada nova tentativa. Esse valor de atraso de nova tentativa pode ser limitado com um valor máximo.
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
O jitter é uma variância adicionada que usa aleatoriedade para distribuir quando os RPCs são invocados. Google Cloud As bibliotecas de cliente sempre ativam o jitter para novas tentativas. Isso ajuda a distribuir as tentativas sem sobrecarregar o servidor.
O valor aleatório de jitter é calculado com base no atraso da nova tentativa. Antes de cada
tentativa, o algoritmo de nova tentativa vai calcular um valor aleatório entre
[1, RETRY_DELAY]. Esse valor calculado é o atraso aproximado antes que a
solicitação seja enviada ao servidor.
As configurações de nova tentativa a seguir usam 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: atrasar um valor aleatório entre
[1, 100]ms - Tentativa 2: atrasar um valor aleatório entre
[1, 200]ms - Tentativa 3: atrasar um valor aleatório entre
[1, 400]ms - Tentativa 4: atrasar um valor aleatório entre
[1, 500]ms - …
- Tentativa X: atrasar um valor aleatório entre
[1, 500]ms
Exemplos de repetição
Os exemplos a seguir mostram o comportamento de algumas configurações de nova tentativa.
Sem 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 | Tempo de espera para a nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 5000ms | 0ms | 0ms | 5000ms |
Exemplo de nova tentativa
Este exemplo ativa novas tentativas com tempos de espera 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 | Tempo de espera para a nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 1500ms | 0ms | 0ms | 1500ms |
| 2 (Tentar de novo) | 3000ms | 200 ms | 1700ms | 4700ms |
| 3 (tentativa não realizada) | - | 400 ms | - | - |
Exemplo de nova tentativa: tempo limite total mais longo
Este exemplo é semelhante ao primeiro, mas tem um tempo limite total maior para mostrar uma tentativa de repetição 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 | Tempo de espera para a nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 1500ms | 0ms | 0ms | 1500ms |
| 2 (Tentar de novo) | 3000ms | 200 ms | 1700ms | 4700ms |
| 3 (Tentar de novo) | 4900ms | 400 ms | 5100ms | 10000ms |
O terceiro valor de tempo limite da 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 da RPC não pode exceder o tempo limite total e é reduzido para ser o "tempo restante" (10.000 - 5.100 = 4.900).
Exemplo de nova tentativa: tempo limite limitado da RPC
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 | Tempo de espera para a nova tentativa | Chamada invocada | Chamada encerrada |
|---|---|---|---|---|
| 1 | 500 ms | 0ms | 0ms | 500 ms |
| 2 (Tentar de novo) | 1000ms | 200 ms | 700 ms | 1700ms |
| 3 (Tentar de novo) | 1900ms | 400 ms | 2100ms | 4000ms |
Outro exemplo em que o tempo limite da 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 o RPC
ExportAssetsdeAssetServiceClient. Ele configura a RPCExportAssetspara usar as configurações de repetição definidas emcustomRetrySettingse define os códigos que podem ser repetidos comoDEADLINE_EXCEEDED.Crie as configurações para o cliente como
assetSettings:java AssetServiceSettings assetSettings = AssetServiceSettings.create(assetStubSettingsBuilder.build());4.Crie o cliente com as configurações comoassetClient.java try (AssetServiceClient assetClient = AssetServiceClient.create(assetSettings)) { ... }
Repita a etapa 2 para cada RPC que você quer 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
Confira abaixo perguntas frequentes sobre o comportamento de novas tentativas do cliente.
Eu esperava X tentativas, mas foram Y.
A menos que você especifique explicitamente o número máximo de tentativas (além de desativar as configurações de tempo limite), talvez não veja consistentemente o mesmo número de tentativas de repetição. Valores aleatórios de jitter para atraso de RPC dificultam a previsão de quando a solicitação é realmente 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 jitter durante cada
tentativa. O atraso calculado será programado para ser executado no futuro (ou seja, currentTime() + jitteredRetryDelay). Se o tempo de tentativa programado exceder o tempo limite total, a última tentativa de nova tentativa não será feita.
Configurei configurações personalizadas e estou tendo problemas com a cota.
Talvez você tenha configurado o RetrySettings para ser executado de forma muito agressiva. Os valores de nova tentativa padrão são escolhidos pela equipe que opera o serviço.
Considere aumentar o atraso de novas tentativas (atraso inicial e multiplicador de novas tentativas) 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 mais tentativas de repetição, ou ambos. Se esse for o caso, tente aumentar os limites de cota.