Stratégie de nouvelle tentative

Cette page décrit les stratégies de nouvelle tentative, telles que l'intervalle exponentiel tronqué entre les tentatives, pour les requêtes envoyées à Cloud Storage ayant échoué.

Présentation

De nombreux outils Cloud Storage, tels que Cloud Console et la plupart des bibliothèques clientes, utilisent automatiquement une stratégie de nouvelle tentative. Vous n'avez donc généralement pas besoin d'implémenter les vôtres. Si vous mettez en œuvre votre propre stratégie de nouvelle tentative, tenez compte du type de requête et de son idempotence, qui déterminent si la requête peut être relancée en toute sécurité. Pour les requêtes pouvant être relancées en toute sécurité, vous devez généralement utiliser un intervalle exponentiel entre les tentatives tronqué. Voici des requêtes permettant de nouvelles tentatives :

  • toutes les requêtes adressées à Cloud Storage qui renvoient les codes de réponse HTTP 5xx, y compris les importations et les téléchargements de données ou de métadonnées ;

  • requêtes envoyées à Cloud Storage qui renvoient un code de réponse HTTP 408 ;

  • requêtes envoyées à Cloud Storage qui renvoient un code de réponse HTTP 429, à l'exception des requêtes qui importent des données à l'aide d'importations avec reprise ;

  • les délais d'expiration de sockets et les déconnexions TCP.

Pour en savoir plus, consultez les codes d'état et d'erreur pour JSON et XML.

Algorithme de l'intervalle exponentiel entre les tentatives

L'intervalle exponentiel entre les tentatives tronqué est une stratégie standard de traitement des erreurs pour les applications réseau, où un client relance régulièrement une requête ayant échoué en observant des délais croissants entre les tentatives.

Un algorithme d'intervalle exponentiel entre les tentatives relance les requêtes de manière exponentielle, en augmentant le temps d'attente entre les tentatives jusqu'à ce que la durée maximale de l'intervalle exponentiel soit atteinte. Voici un exemple :

  1. Envoyez une requête à Cloud Storage.

  2. Si la requête échoue, attendez 1 + random_number_milliseconds secondes, puis effectuez une nouvelle tentative.

  3. Si la requête échoue, attendez 2 + random_number_milliseconds secondes, puis effectuez une nouvelle tentative.

  4. Si la requête échoue, attendez 4 + random_number_milliseconds secondes, puis effectuez une nouvelle tentative.

  5. Poursuivez ainsi jusqu'à atteindre la valeur maximum_backoff.

  6. Continuez d'attendre et de réessayer jusqu'à une durée maximale (deadline) mais n'augmentez pas le délai d'attente maximum_backoff entre les nouvelles tentatives.

où :

  • Le temps d'attente correspond à min((2n +random_number_milliseconds), maximum_backoff), avec n incrémenté de 1 pour chaque itération (requête).

  • random_number_milliseconds correspond à un nombre aléatoire de millisecondes inférieur ou égal à 1 000. Cela permet d'éviter les cas où de nombreux clients sont synchronisés et effectuent tous une nouvelle tentative au même moment, envoyant des requêtes par vagues synchronisées. La valeur de random_number_milliseconds est recalculée après chaque nouvelle tentative de la requête.

  • La valeur maximum_backoff est généralement définie sur 32 ou 64 secondes. La valeur appropriée dépend du cas d'utilisation.

Vous pouvez continuer à effectuer des nouvelles tentatives lorsque vous atteignez le délai maximum_backoff, mais nous vous recommandons d'abandonner votre requête après un certain temps d'échec afin d'éviter que votre application ne cesse de répondre. Par exemple, si un client utilise un délai maximum_backoff de 64 secondes, une fois celui-ci atteint, il peut effectuer une nouvelle tentative toutes les 64 secondes. Le client arrête ensuite de nouvelles tentatives après un temps limite deadline de 600 secondes.

Le temps d'attente des clients entre les tentatives et le nombre de tentatives qu'ils peuvent effectuer dépendent du cas d'utilisation et des conditions du réseau. Par exemple, les clients mobiles d'une application peuvent avoir besoin d'effectuer davantage de tentatives et à des intervalles plus longs que les clients de bureau de la même application.

Si les nouvelles tentatives de requête échouent après le dépassement de la valeur maximum_backoff plus tout temps supplémentaire autorisé pour les nouvelles tentatives, signalez ou enregistrez une erreur à l'aide de l'une des méthodes répertoriées sur la page Assistance.

Idempotence

Pour déterminer si vous pouvez réessayer d'envoyer une requête ayant échoué à Cloud Storage, vérifiez si la requête est idempotente, ce qui signifie que l'application d'une même opération à plusieurs reprises a le même effet sur l'état de la ressource ciblée. Les opérations idempotentes peuvent généralement être relancées en toute sécurité.

Voici des exemples de conditions satisfaisant l'idempotence :

  • L'opération a le même effet observable sur la ressource ciblée, même lorsqu'elle des requêtes y sont constamment envoyées.

  • L'opération ne peut aboutir qu'une seule fois.

  • Cette opération n'a aucun effet observable sur l'état de la ressource ciblée.

Par exemple, une requête de liste de buckets aura le même effet même si la requête aboutit plusieurs fois En revanche, une opération telle que la création d'une notification Pub/Sub n'est pas idempotente, car elle crée un ID de notification chaque fois que la requête aboutit.

Idempotence conditionnelle

Un sous-ensemble de requêtes est idempotent sous conditions, ce qui signifie que les requêtes ne sont idempotentes que si elles incluent des arguments facultatifs spécifiques. Les opérations soumises à une règle de sécurité doivent être relancées par défaut uniquement si la condition est remplie. Cloud Storage accepte les conditions préalables et les ETag comme conditions pour les requêtes.

Stratégie de nouvelle tentative par outil Cloud Storage

Cliquez sur les onglets ci-dessous pour afficher les recommandations de stratégie de nouvelle tentative pour chaque outil Cloud Storage.

Console

Cloud Console envoie des requêtes à Cloud Storage en votre nom et gère tout intervalle nécessaire entre les tentatives.

gsutil

gsutil relance les erreurs répertoriées dans la section Présentation sans que vous n'ayez à intervenir. Vous devrez peut-être prendre des mesures pour d'autres erreurs, par exemple celles ci-dessous :

  • Identifiants incorrects ou autorisations insuffisantes

  • Réseau inaccessible en raison d'un problème de configuration du proxy

  • Opérations individuelles qui échouent dans une commande où vous utilisez l'option de niveau supérieur -m.

Pour les erreurs permettant des nouvelles tentatives, gsutil relance les requêtes à l'aide d'une stratégie d'intervalle exponentiel tronqué entre les tentatives. Par défaut, gsutil effectue 23 nouvelles tentatives sur à des intervalles de 1+2+4+8+16+32+60... secondes pour une durée totale d'environ 10 minutes :

  • Si une requête échoue, attendez une période aléatoire comprise entre [0..1] secondes et réessayez ;
  • si la requête échoue à nouveau, attendez une période aléatoire comprise entre [0..2] secondes et réessayez ;
  • si la requête échoue à nouveau, attendez une période aléatoire comprise entre [0..4] secondes et réessayez ;
  • et ainsi de suite jusqu'à 23 nouvelles tentatives, chaque période de nouvelle tentative étant limitée par une durée maximum par défaut de 60 secondes.

Vous pouvez configurer le nombre de nouvelles tentatives et le délai maximal entre chaque tentative en modifiant les variables de configuration num_retries et max_retry_delay dans la section "[Boto]" du fichier de configuration .boto.

Pour les transferts de données à l'aide des commandes gsutil cp et rsync, gsutil offre une fonctionnalité de répétition supplémentaire sous la forme des transferts avec reprise.

Bibliothèques clientes

C++

Par défaut, la bibliothèque cliente C++ utilise l'intervalle exponentiel entre les tentatives.

C#

Par défaut, la bibliothèque cliente C# utilise un intervalle exponentiel entre les tentatives.

Go

Par défaut, la bibliothèque cliente Go utilise l'intervalle exponentiel entre les tentatives.

Java

Par défaut, la bibliothèque cliente Java utilise l'intervalle exponentiel entre les tentatives.

Node.js

La bibliothèque cliente Node.js peut utiliser automatiquement utiliser des stratégies d'intervalle exponentiel entre les tentatives pour relancer des requêtes avec le paramètre autoRetry.

PHP

Par défaut, la bibliothèque cliente PHP utilise l'intervalle exponentiel entre les tentatives.

Python

Par défaut, les opérations sont compatibles avec les nouvelles tentatives pour les codes d'erreur suivants :

  • Erreurs de connexion :
    • requests.exceptions.ConnectionError
    • requests.exceptions.ChunkedEncodingError (uniquement pour les opérations de récupération ou d'envoi de données de charge utile à des objets, telles que les importations et les téléchargements)
  • Codes HTTP :
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
    • 508 Resource Limit Exceeded

Les opérations via Python utilisent les paramètres par défaut suivants pour l'intervalle exponentiel entre les tentatives :

Paramètre Valeur par défaut (en secondes)
Durée d'attente initiale 1
Multiplicateur de la durée d'attente par itération 2
Durée d'attente maximale 60
Deadline par défaut 120

Un sous-ensemble d'opérations n'est idempotent que s'il inclut des arguments facultatifs spécifiques. Les opérations dont la sécurité est conditionnelle ne sont relancées par défaut que si la condition est satisfaite. Actuellement, ces conditions incluent les suivantes :

  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED

    • Vous pouvez effectuer de nouvelles tentatives si generation ou if_generation_match a été transmis en tant qu'argument à la méthode. Les méthodes n'acceptent souvent que l'un de ces deux paramètres.
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED

    • Vous pouvez effectuer de nouvelles tentatives si if_metageneration_match a été transmis en tant qu'argument à la méthode.
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

    • Vous pouvez effectuer de nouvelles tentatives si la méthode insère un etag dans le corps de la requête JSON. Pour HMACKeyMetadata.update(), cela signifie que l'eTag doit être défini sur l'objet HMACKeyMetadata lui-même. Pour la méthode set_iam_policy() sur d'autres classes, cela signifie que l'eTag doit être défini dans l'argument "policy" transmis à la méthode.

Règles pour les nouvelles tentatives

Un paramètre retry est ajouté à la signature de la méthode pour les opérations sécurisées ou dont la sécurité est conditionnelle pour les nouvelles tentatives. La valeur par défaut pour ces paramètres est l'une des suivantes :

  • DEFAULT_RETRY
  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

Pour modifier le comportement de nouvelle tentative par défaut, créez une copie de l'objet google.cloud.storage.retry.DEFAULT_RETRY en l'appelant avec une méthode with_XXX. Notez que with_predicate n'est pas compatible avec les opérations de récupération ou d'envoi de données de charge utile à des objets, telles que les importations et les téléchargements. Nous vous recommandons de modifier les attributs un par un. Pour en savoir plus, consultez la documentation de référence sur google-api-core Retry.

Pour configurer votre propre nouvelle tentative conditionnelle, créez un objet ConditionalRetryPolicy et encapsulez votre objet Retry personnalisé avec DEFAULT_RETRY_IF_GENERATION_SPECIFIED, DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, ou DEFAULT_RETRY_IF_ETAG_IN_JSON.

Voici des exemples de nouvelles tentatives personnalisées :

  • blob.reload() utilise DEFAULT_RETRY par défaut. Pour ignorer ce comportement afin que la fonction ne soit pas réessayée, appelez-la en tant que blob.reload(retry=None).

  • bucket.update() utilise DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED par défaut. Pour ignorer ce comportement afin que la fonction soit réessayée même si le numéro de métagénération n'est pas spécifié, appelez-la comme suit :

    from google.cloud.storage.retry import DEFAULT_RETRY
    bucket.update(retry=DEFAULT_RETRY)
  • bucket.list_blobs() utilise DEFAULT_RETRY par défaut. Pour ignorer ce comportement afin que l'appel d'API effectue une nouvelle tentative avec un délai de 20 secondes au lieu du délai par défaut de 120 secondes, appelez-la comme suit :

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

Ruby

Par défaut, la bibliothèque cliente Ruby utilise l'intervalle exponentiel entre les tentatives.

API REST

Lorsque vous appelez directement l'API JSON ou XML, vous devez utiliser l'algorithme d'intervalle exponentiel entre les tentatives pour mettre en œuvre votre propre stratégie de nouvelles tentatives.

Idempotence des opérations

Le tableau suivant répertorie les opérations Cloud Storage qui entrent dans chaque catégorie d'idempotence.

Idempotence Opérations
Toujours idempotente
  • Toutes les requêtes get et list
  • Insérer ou supprimer des buckets
  • Tester les stratégies et autorisations IAM d'un bucket
  • Verrouiller les règles de conservation
  • Supprimer une clé HMAC ou une notification Pub/Sub
Idempotente sous conditions
  • Requêtes de mise à jour/correctif pour les buckets avec IfMetagenerationMatch ou ETag comme condition préalable HTTP
  • Requêtes de mise à jour/correctif pour les objets avec IfMetagenerationMatch ou ETag comme condition préalable HTTP
  • Définir une stratégie IAM de bucket avec un eTag en tant que condition préalable HTTP ou dans le corps de la ressource
  • Mettre à jour une clé HMAC avec un eTag en tant que condition préalable HTTP ou dans le corps de la ressource
  • Insérer, copier, rédiger ou réécrire des objets avec ifGenerationMatch
  • Supprimer un objet avec ifGenerationMatch (ou avec un numéro de génération pour les versions d'objet)
Jamais idempotente
  • Créer une clé HMAC
  • Créer une notification Pub/Sub
  • Créer, supprimer ou envoyer des requêtes de correctif/mise à jour pour les LCA de buckets et d'objets, ou pour des LCA d'objet par défaut

Étape suivante