Estrategia de reintentos

En esta página, se describen las estrategias de reintentos, como la retirada exponencial truncada para las solicitudes fallidas a Cloud Storage.

Descripción general

Para decidir si se debe reintentar una solicitud con errores a Cloud Storage, considera el tipo de solicitud y su idempotencia, que determina si la operación es segura para reintentarla. En general, debes usar una retirada exponencial truncada para reintentar los siguientes tipos de solicitudes:

  • Todas las solicitudes a Cloud Storage que muestran códigos de respuesta HTTP 5xx y 429, incluidas las cargas y descargas de datos o metadatos

  • Cargas reanudables que muestran códigos de respuesta HTTP 408

  • Tiempos de espera de sockets agotados y desconexiones de TCP

Si quieres obtener más información, consulta los códigos de estado y error para JSON y XML.

Algoritmo de retirada exponencial

La retirada exponencial truncada es una estrategia estándar de manejo de errores para aplicaciones de red en la que el cliente vuelve a intentar de forma periódica una solicitud con errores, cada vez con más frecuencia entre las solicitudes.

Un algoritmo de retirada exponencial vuelve a intentar las solicitudes de forma exponencial, lo que aumenta el tiempo de espera entre los reintentos hasta un tiempo de retirada máximo. A continuación, se presenta un ejemplo:

  1. Haz una solicitud a Cloud Storage.

  2. Si la solicitud falla, espera 1 + random_number_milliseconds segundos y vuelve a intentar la solicitud.

  3. Si la solicitud falla, espera 2 + random_number_milliseconds segundos y vuelve a intentar la solicitud.

  4. Si la solicitud falla, espera 4 + random_number_milliseconds segundos y vuelve a intentar la solicitud.

  5. Y así sucesivamente, hasta un tiempo de maximum_backoff.

  6. Continúa con la espera y los reintentos hasta una cantidad de tiempo máxima (deadline), pero no aumentes el período de espera de maximum_backoff entre los reintentos.

Donde:

  • El tiempo de espera es min((2n +random_number_milliseconds), maximum_backoff), con n incrementado en 1 para cada iteración (solicitud).

  • random_number_milliseconds es un número al azar de milisegundos menor o igual que 1,000. Esto ayuda a evitar los casos en los que muchos clientes se sincronizan y se vuelven a intentar a la vez, lo que hace que se envíen solicitudes sincronizadas en etapas. El valor de random_number_milliseconds se vuelve a calcular después de cada reintento de solicitud.

  • maximum_backoff suele ser de 32 o 64 segundos. El valor apropiado depende del caso práctico.

Puedes continuar con los reintentos una vez que alcances el tiempo maximum_backoff, pero recomendamos que tu solicitud falle después de un período para evitar que tu aplicación no responda. Por ejemplo, si un cliente usa un tiempo maximum_backoff de 64 segundos, luego de alcanzar este valor, puede volver a intentarlo cada 64 segundos. Luego, el cliente deja de reintentarlo después de un deadline de 600 segundos.

El tiempo que los clientes deben esperar entre los reintentos y la cantidad de reintentos que deben realizar dependen de tu caso práctico y las condiciones de la red. Por ejemplo, es posible que los clientes móviles de una aplicación deban intentar más veces y por intervalos más largos, en comparación con los clientes de escritorio de la misma aplicación.

Si las solicitudes de reintento fallan después de exceder el maximum_backoff y cualquier tiempo adicional permitido para los reintentos, informa o registra un error mediante uno de los métodos enumerados en Asistencia y ayuda.

Idempotencia

A fin de determinar si es seguro reintentar una solicitud con errores en Cloud Storage, considera si la solicitud idempotente, lo que significa que la aplicación de la misma operación varias veces tiene el mismo efecto sobre el estado del recurso de destino. Generalmente, se puede reintentar ejecutar las operaciones de idempotente de forma segura.

Los siguientes son ejemplos de condiciones que satisfacen la idempotencia:

  • La operación tiene el mismo efecto observable en el recurso objetivo incluso cuando se solicita de forma continua.

  • La operación solo se realiza una vez.

  • La operación no tiene un efecto observable en el estado del recurso de destino.

Por ejemplo, una solicitud para crear una lista de buckets tiene el mismo efecto, incluso si la solicitud es exitosa varias veces. Por otro lado, una operación como crear una nueva notificación de Pub/Sub no es idempotente, ya que crea un nuevo ID de notificación cada vez que la solicitud se realiza correctamente.

Idempotencia condicional

Un subconjunto de solicitudes es condicionalmente idempotente, lo que significa que solo son idempotentes si incluyen argumentos opcionales específicos. Las operaciones condicionalmente seguras para su reintento solo deben reintentarse de forma predeterminada si se aprueba el caso de la condición. Cloud Storage acepta condiciones previas y ETag como casos de condición para las solicitudes.

Estrategia de reintento por la herramienta de Cloud Storage

Haz clic en las pestañas que están a continuación para ver las recomendaciones de las estrategias de reintento de cada herramienta de Cloud Storage.

Console

Cloud Console envía solicitudes a Cloud Storage en tu nombre y controla las retiradas necesarias.

gsutil

gsutil vuelve a intentar los errores enumerados en la sección Descripción general sin que debas realizar acciones adicionales. Es posible que debas tomar medidas para otros errores, como los siguientes:

  • Credenciales no válidas o permisos insuficientes.

  • No se puede acceder a la red debido a un problema de configuración del proxy.

  • Operaciones individuales que fallan en un comando en el que usas la marca de nivel superior -m

Para los errores que se pueden intentar de nuevo, gsutil vuelve a intentar las solicitudes mediante una estrategia de retirada exponencial binaria truncada. De forma predeterminada, gsutil vuelve a intentarlo 23 veces en 1+2+4+8+16+32+60… segundos durante alrededor de 10 minutos:

  • Si una solicitud falla, espera un período aleatorio entre [0..1] segundos y vuelve a intentarlo.
  • Si la solicitud falla nuevamente, espera un período aleatorio entre [0..2] segundos y vuelve a intentarlo.
  • Si la solicitud falla nuevamente, espera un período aleatorio entre [0..4] segundos y vuelve a intentarlo.
  • Y así sucesivamente, hasta 23 reintentos, con cada período de reintento limitado por un máximo predeterminado de 60 segundos.

Para configurar la cantidad de reintentos y el retraso máximo de cualquier reintento individual, edita las variables de configuración num_retries y max_retry_delay en la sección "[Boto]" de archivo de configuración .boto.

Para las transferencias de datos que usan los comandos cp y rsync de gsutil, gsutil proporciona una funcionalidad de reintento adicional en la forma de transferencias reanudables.

Bibliotecas cliente

C++

La biblioteca cliente C++ usa la retirada exponencial de forma predeterminada.

C#

La biblioteca cliente C# usa la retirada exponencial de forma predeterminada.

Comienza a usarlo

La biblioteca cliente de Go usa la retirada exponencial de forma predeterminada.

Java

La biblioteca cliente de Java usa la retirada exponencial de forma predeterminada.

Node.js

Node.js puede usar automáticamente estrategias de retirada para reintentar solicitudes con el parámetro autoRetry.

PHP

La biblioteca cliente de PHP usa la retirada exponencial de forma predeterminada.

Python

Para la estrategia de reintento, la biblioteca cliente de Python distingue entre operaciones multimedia y no multimedia:

  • Las operaciones multimedia incluyen todas las acciones que recuperan o envían datos de carga útil a los objetos. Por ejemplo, se incluyen todos los métodos de un Blob que comienzan con las palabras “upload” o “download”, así como Client.download_blob_to_file.

  • Las operaciones que no son multimedia son acciones que solo manejan metadatos de objetos.

De forma predeterminada, las operaciones multimedia y no multimedia admiten reintentos para los siguientes códigos de error:

  • Errores de conexión
    • requests.exceptions.ConnectionError
    • requests.exceptions.ChunkedEncodingError (solo llamadas a la API multimedia)
  • Códigos HTTP:
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
    • 508 Resource Limit Exceeded

Las operaciones a través de Python usan la siguiente configuración predeterminada para la retirada exponencial:

Parámetro de configuración predeterminado Llamadas de multimedia Llamadas no relacionadas con multimedia
Tiempo de espera inicial (segundos) 1 1
Multiplicador de tiempo de espera por iteración (segundos) 2 2
Tiempo máximo de espera (segundos) 64 60
Plazo predeterminado (segundos) 600 120
Implementación del Jitter No

Un subconjunto de operaciones multimedia y no multimedia solo es idempotente si incluyen argumentos opcionales específicos. Las operaciones que son seguras para reintentarse solo lo hacen de forma predeterminada si se aprueba el caso de condición. Actualmente, estas condiciones incluyen lo siguiente:

  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED

    • Se aprobó la seguridad de reintentar if generation o if_generation_match como argumento del método. A menudo, los métodos solo aceptan uno de estos dos parámetros.
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED

    • Es seguro reintentarlo si if_metageneration_match se aprobó como argumento del método.
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

    • Es seguro reintentarlo si el método inserta un etag en el cuerpo de la solicitud JSON. Para HMACKeyMetadata.update(), esto significa que la ETag se debe configurar en el objeto HMACKeyMetadata. Para el método set_iam_policy() en otras clases, significa que la ETag se debe establecer en el argumento de la “política” que se pasó al método.

Políticas de reintentos para las operaciones multimedia

Para las operaciones multimedia, puedes configurar el argumento num_retries de los métodos de carga a fin de especificar la cantidad de reintentos de carga. Según la configuración predeterminada, solo se reintentan las cargas con la condición if_metageneration_match para garantizar la idempotencia. Si se configura el argumento num_retries, se anula el comportamiento predeterminado y se garantizan los reintentos incluso sin la condición if_metageneration_match.

Políticas de reintentos para las operaciones que no son multimedia

Las operaciones que no son multimedia, y que son seguras o son condicionalmente seguras para reintentarse, tienen un parámetro retry agregado a la firma de su método. El valor predeterminado para estos parámetros es uno de los siguientes:

  • DEFAULT_RETRY
  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

Para modificar el comportamiento de reintento predeterminado, crea una copia del objeto google.cloud.storage.retry.DEFAULT_RETRY llamándolo con un método with_XXX. Por ejemplo, para modificar el plazo predeterminado a 30 segundos, pasa retry=DEFAULT_RETRY.with_deadline(30). Te recomendamos modificar los atributos uno por uno. Para obtener más información, consulta la Operaciones de reintento de google-api-core.

Para configurar tu propio reintento condicional, crea un objeto ConditionalRetryPolicy y une tu objeto Retry personalizado con DEFAULT_RETRY_IF_GENERATION_SPECIFIED, DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED. o DEFAULT_RETRY_IF_ETAG_IN_JSON.

Los siguientes son ejemplos de reintentos condicionales personalizados:

  • blob.reload() usa DEFAULT_RETRY de forma predeterminada. A fin de anular esto para que la función no se vuelva a intentar, llámala como blob.reload(retry=None).

  • bucket.update() usa DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED de forma predeterminada. Para anular esto, de modo que la función se vuelva a intentar incluso si la cantidad de metageneración no se especifica, llámalo de la siguiente manera:

    from google.cloud.storage.retry import DEFAULT_RETRY
    bucket.update(retry=DEFAULT_RETRY)
  • bucket.list_blobs() usa DEFAULT_RETRY de forma predeterminada. Para anular esto, de modo que la llamada a la API se vuelva a intentar con un plazo de 20 segundos en lugar de los 120 segundos predeterminados, llámalo de la siguiente manera:

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

Ruby

La biblioteca cliente de Ruby usa la retirada exponencial de forma predeterminada.

API de REST

Cuando llames a la API de XML o JSON directamente, debes usar el algoritmo de retirada exponencial para implementar tu propia estrategia de reintento.

Idempotencia de operaciones

En la siguiente tabla, se describen las operaciones de Cloud Storage que corresponden a cada categoría de idempotencia.

Idempotencia Operations
Siempre idempotente
  • Todas las solicitudes get y list
  • Inserta o borra buckets
  • Políticas y permisos de IAM del bucket de prueba
  • Bloquear políticas de retención
  • Borra una clave HMAC o una notificación de Pub/Sub
Condicionalmente idempotente
  • Solicitudes de actualización o parche para buckets con IfMetagenerationMatch o ETag como condición previa HTTP
  • Solicitudes de actualización o parche para objetos con IfMetagenerationMatch o ETag como condición previa HTTP
  • Establece una política de IAM del bucket con ETag como condición previa HTTP o en el cuerpo del recurso
  • Actualiza una clave HMAC con ETag como condición previa HTTP o en el cuerpo del recurso
  • Inserta, copia, redacta o reescribe objetos con ifGenerationMatch
  • Borra un objeto con ifGenerationMatch (o con un número de generación para versiones de objetos)
Nunca idempotente
  • Crea una clave HMAC
  • Crea una notificación de Pub/Sub
  • Crea, borra o envía solicitudes de parche o actualización para las LCA de buckets y objetos o las LCA de objeto predeterminadas

¿Qué sigue?