Configura reintentos del cliente

Las bibliotecas cliente de Cloud para Java usan reintentos para controlar errores transitorios inesperados (es decir, el servidor no está disponible temporalmente). Varios intentos pueden generar una respuesta exitosa del servidor.

El equipo que opera el servicio en la nube selecciona los valores de reintento predeterminados. Estos valores de reintento se configuran por RPC. Un servicio puede optar por habilitar solo los reintentos para un subconjunto de RPCs. Es posible que cada RPC de un servicio esté configurada de manera diferente.

Parámetros de reintento

Las bibliotecas cliente tienen dos tipos de parámetros de reintento para configurar:

  1. Código de estado de reintento: Es el conjunto de códigos de estado para reintentar.
  2. Tiempo de espera para reintentar o límites de intentos: RetrySettings configurables para definir los límites.

Ubicación predeterminada de la configuración de reintentos de RPC

Las configuraciones de reintento predeterminadas se definen en el archivo {Client}StubSettings generado. Si se usa el RPC de ExportAssets en Java-Asset v3.64.0 como ejemplo, las configuraciones predeterminadas de reintentos se definen en los siguientes lugares:

  • Códigos de estado de reintento: Se configuran en el archivo AssetServiceStubSettings.java. Ejemplo:

    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 reintento: Se configuran en el archivo AssetServiceStubSettings.java. Ejemplo:

    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();
    

Ambas configuraciones se asignan a la RPC en el archivo AssetServiceStubSettings.java. Ejemplo:

builder
  .exportAssetsSettings()
  .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes"))
  .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params"));

Conceptos de reintentos de la biblioteca cliente

Habilitar los reintentos permite que una RPC intente varias veces lograr una llamada exitosa. Una llamada exitosa es una respuesta de un servidor que devuelve un código de estado OK (de gRPC) o un código de estado 2xx (de HttpJson).

Intento en comparación con operación

La siguiente configuración de RetrySettings modifica la configuración de reintentos para el intento y la operación de una 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();

Un intento de RPC es el intento individual que se realiza, y una operación de RPC es una colección de todos los intentos realizados. Una sola invocación de RPC tendrá uno o más intentos en una sola operación.

Los límites de RPC individuales (un intento) se controlan con los siguientes parámetros de configuración:

Los límites totales de RPC (una operación) se controlan con los siguientes parámetros de configuración:

  • setTotalTimeout: Se permitió el tiempo de espera total para toda la operación.
  • setMaxAttempts: Es la cantidad máxima de intentos permitidos.

Cuándo se reintenta una RPC

Se volverá a intentar una RPC cuando ocurran las dos situaciones siguientes:

  • La biblioteca recibe un código de estado que no es correcto y se marca que se puede volver a intentar.
  • Una invocación de RPC supera los límites individuales de RPC, pero aún se encuentra dentro de los límites totales de RPC.

Si solo un caso es verdadero o si ninguno lo es, no se volverá a intentar la RPC.

Por ejemplo, si no se superó el tiempo de espera total, pero el intento más reciente recibe un código de estado que no se puede reintentar.

Además, cuando configures los límites de RPC, puedes configurar los límites para cada intento, así como los límites totales de RPC. El algoritmo de reintento garantizará que los límites de un intento individual se encuentren dentro de los límites totales de la RPC.

Retirada exponencial

La retirada exponencial volverá a intentar las solicitudes con un retraso cada vez mayor entre cada reintento. Este valor de demora de reintento se puede limitar con un valor máximo de demora de reintento.

Por ejemplo, las siguientes configuraciones de reintento pueden generar los siguientes tiempos de demora:

Initial Retry Delay: 100ms
Retry Delay Multiplier: 2.0
Max Retry Delay: 500ms
  • Intento 1: Retraso de 100 ms
  • Intento 2: Retraso de 200 ms
  • Intento 3: Retraso de 400 ms
  • Intento 4: Retraso de 500 ms
  • Intento X: Retraso de 500 ms
Establece un límite para las operaciones de RPC configurando el valor de TotalTimeout o MaxAttempts.

Jitter

La fluctuación es una varianza agregada que usa la aleatoriedad para distribuir el momento en que se invocan las RPC. Google Cloud Las bibliotecas cliente siempre habilitan la fluctuación para los reintentos. Esto ayuda a distribuir los reintentos sin sobrecargar el servidor.

El valor aleatorio de fluctuación se calcula en función de la demora en el reintento. Antes de cada intento, el algoritmo de reintento calculará un valor aleatorio entre [1, RETRY_DELAY]. Este valor calculado es la demora aproximada antes de que se envíe la solicitud al servidor.

Las siguientes configuraciones de reintento utilizan la retirada exponencial y el jitter.

Initial Retry Delay: 100ms
Retry Delay Multiplier: 2.0
Max Retry Delay: 500ms

Esto podría generar los siguientes tiempos de demora:

  • Intento 1: Demora un valor aleatorio entre [1, 100] ms
  • Intento 2: Demora un valor aleatorio entre [1, 200] ms
  • Intento 3: Demora un valor aleatorio entre [1, 400] ms
  • Intento 4: Retrasa un valor aleatorio entre [1, 500] ms
  • Intento X: Retrasa un valor aleatorio entre [1, 500] ms
Establece un límite para las operaciones de RPC configurando el valor de TotalTimeout o MaxAttempts.

Ejemplos de reintentos

En los siguientes ejemplos, se muestra el comportamiento de algunas configuraciones de reintentos.

No volver a intentar

En este ejemplo, se inhabilitan los reintentos.

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, este comportamiento se puede configurar con este ejemplo:

RetrySettings defaultNoRetrySettings =
    RetrySettings.newBuilder()
    .setLogicalTimeoutDuration(Duration.ofMillis(5000L))
    .build();

En la siguiente tabla, se muestran los intentos:

Número de intento Tiempo de espera de RPC Intervalo de reintento Llamada invocada Llamada finalizada
1 5000 ms 0 ms 0 ms 5000 ms

Ejemplo de reintento

En este ejemplo, se habilitan los reintentos con los tiempos de espera y los retrasos 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();

En la siguiente tabla, se muestran los intentos:

Número de intento Tiempo de espera de RPC Intervalo de reintento Llamada invocada Llamada finalizada
1 1,500 ms 0 ms 0 ms 1,500 ms
2 (Reintentar) 3000 ms 200 ms 1700 ms 4700 ms
3 (No se intentó el reintento) - 400 ms - -

Ejemplo de reintento: tiempo de espera total más largo

Este ejemplo es similar al primer ejemplo de reintento, pero tiene un tiempo de espera total más largo para mostrar un intento de reintento adicional y el tiempo de espera de RPC limitado para el último intento de reintento.

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();

En la siguiente tabla, se muestran los intentos:

Número de intento Tiempo de espera de RPC Intervalo de reintento Llamada invocada Llamada finalizada
1 1,500 ms 0 ms 0 ms 1,500 ms
2 (Reintentar) 3000 ms 200 ms 1700 ms 4700 ms
3 (Reintentar) 4900 ms 400 ms 5100 ms 10,000 ms

El tercer valor de tiempo de espera de RPC para reintentos está limitado debido al valor de tiempo de espera total. Si se usa el multiplicador (2.0) con el valor de tiempo de espera anterior (3,000 ms), se obtiene un tiempo de espera de RPC de 6,000 ms. Sin embargo, el tiempo de espera de RPC no debe exceder el tiempo de espera total y se reduce para ser el "tiempo restante" (10,000 - 5,100 = 4,900).

Ejemplo de reintento: Se agotó el tiempo de espera de 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();

En la siguiente tabla, se muestran los intentos:

Número de intento Tiempo de espera de RPC Intervalo de reintento Llamada invocada Llamada finalizada
1 500 ms 0 ms 0 ms 500 ms
2 (Reintentar) 1,000 ms 200 ms 700 ms 1700 ms
3 (Reintentar) 1900 ms 400 ms 2,100 ms 4,000 ms

Otro ejemplo en el que el tiempo de espera de RPC se limita para no exceder el tiempo de espera total.

Cómo configurar parámetros de reintento personalizados para una RPC

En el siguiente ejemplo, se usa la biblioteca cliente de Java-Asset:

  1. Crea la clase RetrySettings con tus configuraciones personalizadas:

    RetrySettings customRetrySettings =
      RetrySettings.newBuilder()
        // ... Retry Configurations
        .build();
    RetrySettings customRetrySettings2 =
      RetrySettings.newBuilder()
        // ... Retry Configurations
        .build();
    
  2. Crea el objeto StubSettings.Builder para tu cliente y configúralo para la 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));
    

    El fragmento de código proporcionado establece parámetros de configuración de reintentos personalizados para la RPC ExportAssets de AssetServiceClient. Configura la RPC de ExportAssets para que use la configuración de reintento establecida en customRetrySettings y establece los códigos que se pueden reintentar en DEADLINE_EXCEEDED.

  3. Crea la configuración del cliente como assetSettings: java AssetServiceSettings assetSettings = AssetServiceSettings.create(assetStubSettingsBuilder.build()); 4.Crea el cliente con la configuración como assetClient. java try (AssetServiceClient assetClient = AssetServiceClient.create(assetSettings)) { ... }

Repite el paso 2 para cada RPC que quieras configurar. Por ejemplo:

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));

Preguntas frecuentes

A continuación, se incluyen preguntas frecuentes sobre el comportamiento de reintento del cliente.

Esperaba X intentos, pero se intentó Y veces.

A menos que especifiques de forma explícita la cantidad máxima de intentos (junto con la inhabilitación de la configuración de tiempo de espera), es posible que no veas de forma coherente la misma cantidad de reintentos. Los valores aleatorios de fluctuación para la demora de RPC dificultan la predicción del momento en que se envía la solicitud.

La RPC devolvió un error antes de que se alcanzara el valor de tiempo de espera total.

El algoritmo de reintentos calculará el valor de demora de reintento con fluctuaciones durante cada intento de reintento. La demora calculada para el reintento se programará para ejecutarse en el futuro (es decir, currentTime() + jitteredRetryDelay). Si la hora programada para el intento supera el tiempo de espera total, no se realizará el intento final de reintento.

Configuré parámetros personalizados y tengo problemas con las cuotas.

Es posible que hayas configurado RetrySettings para que se ejecute de forma demasiado agresiva. El equipo que opera el servicio elige los valores de reintento predeterminados.

Considera aumentar el retraso de reintento (retraso de reintento inicial y multiplicador de reintento) para que los reintentos estén más espaciados y sean menos frecuentes. Ten en cuenta que esto puede generar una respuesta más lenta.

Tu caso de uso puede requerir una respuesta más rápida o más intentos de reintento, o ambos. Si es así, intenta aumentar los límites de cuota.