Cette page traite des préconditions de requête, que vous utilisez pour empêcher les requêtes de s'appliquer à une ressource lorsque celle-ci est dans un état inattendu.
Introduction
Lorsque des préconditions sont utilisées dans une requête adressée à Cloud Storage, la requête n'est exécutée que si la ressource ciblée répond aux critères définis dans les préconditions. Les vérifications de préconditions vous permettent de vous assurer qu'un bucket ou un objet se trouve dans l'état attendu, ce qui vous permet d'effectuer des mises à jour de lecture-modification-écriture et des opérations conditionnelles de façon sécurisée.
Les préconditions sont souvent utilisées pour éviter les conditions de concurrence dans les requêtes de mutation telles que les importations, les suppressions ou les mises à jour de métadonnées. Des conditions de concurrence peuvent survenir lorsque la même requête est envoyée à plusieurs reprises ou lorsque des processus indépendants tentent de modifier la même ressource. Pour en savoir plus, consultez Exemples de conditions de concurrence et de corruption de données. Les préconditions sont également utilisées lors de la récupération des métadonnées et des données d'objet dans des requêtes successives, pour garantir que l'objet n'a pas changé entre les deux requêtes.
Critères de précondition
Cloud Storage accepte l'utilisation de plusieurs propriétés de ressource immuables différentes dans les préconditions :
- Numéros de génération et de métagénération
- ETags
- La date
Last-Modified(disponible uniquement lors de l'obtention de données ou de métadonnées d'objet à l'aide de l'API XML)
Le tableau suivant recense les préconditions acceptées par l'API JSON et l'API XML :
| API JSON | API XML | Description |
|---|---|---|
Paramètre de requête ifGenerationMatch |
En-tête x-goog-if-generation-match |
La requête est exécutée si le paramètre generation de la ressource cible correspond à la valeur utilisée dans la précondition. Si les valeurs ne correspondent pas, la requête échoue avec une réponse 412 Precondition Failed. |
Paramètre de requête ifMetagenerationMatch |
En-tête x-goog-if-metageneration-match |
La requête est exécutée si le paramètre metageneration de la ressource cible correspond à la valeur utilisée dans la précondition. Si les valeurs ne correspondent pas, la requête échoue avec une réponse 412 Precondition Failed. |
Paramètre de requête ifGenerationNotMatch |
N/A | La requête est exécutée si le paramètre generation de la ressource cible ne correspond pas à la valeur utilisée dans la précondition. Si les valeurs correspondent, la requête échoue avec une réponse 304 Not Modified. |
Paramètre de requête ifMetagenerationNotMatch |
N/A | La requête est exécutée si le paramètre metageneration de la ressource cible ne correspond pas à la valeur utilisée dans la précondition. Si les valeurs correspondent, la requête échoue avec une réponse 304 Not Modified. |
En-tête If-Match |
En-tête If-Match |
Applicable aux requêtes qui récupèrent des données. La requête est exécutée si le paramètre ETag de la ressource cible correspond à la valeur utilisée dans la précondition. Si les valeurs ne correspondent pas, la requête échoue avec une réponse 412 Precondition Failed. |
En-tête If-None-Match |
En-tête If-None-Match |
Applicable aux requêtes qui récupèrent des données. La requête est exécutée si le paramètre ETag de la ressource cible ne correspond pas à la valeur utilisée dans la précondition. Si les valeurs correspondent, la requête échoue avec une réponse 304 Not Modified. |
| N/A | En-tête If-Modified-Since |
La requête est exécutée si la ressource cible a une date Last-Modified ultérieure à la valeur utilisée dans la précondition. Si la ressource cible ne remplit pas cette précondition, la requête échoue avec une réponse 304 Not Modified. |
| N/A | En-tête If-Unmodified-Since |
La requête est exécutée si la ressource cible a une date Last-Modified antérieure ou égale à la valeur utilisée dans la précondition. Si la ressource cible ne remplit pas cette précondition, la requête échoue avec une réponse 412 Precondition Failed. |
Préconditions de composition d'objets
Lors de la composition d'objets, l'API JSON et l'API XML acceptent les préconditions suivantes :
Les préconditions de correspondance de génération et de métagénération pour l'objet de destination.
La précondition de correspondance de génération pour chaque objet source. L'utilisation de cette précondition empêche l'utilisation de composants incorrects dans le cas où un processus indépendant écraserait l'un des composants prévus de la composition. Si vous utilisez des préconditions et qu'un écrasement de ce type se produit, les opérations
composeéchouent avec une réponse412 Precondition Failed.
Préconditions de copie d'objets
Lors de la copie ou de la réécriture d'un objet dans Cloud Storage, l'API JSON et l'API XML permettent l'utilisation de préconditions standards pour l'objet de destination. Chaque API accepte des préconditions supplémentaires pour les objets sources :
L'API JSON accepte les préconditions de génération et de métagénération pour l'objet source, lesquelles sont spécifiées à l'aide de paramètres de requête portant le préfixe
ifSource.Toutes les préconditions acceptées par l'API XML peuvent être utilisées pour l'objet source. Ces préconditions sont spécifiées dans les en-têtes précédés du préfixe
x-goog-copy-source-.
Valeur 0 dans une précondition de correspondance de génération
La précondition de correspondance de génération accepte la valeur 0 comme cas particulier. Lorsqu'une précondition de correspondance de génération avec la valeur 0 est incluse dans une requête, celle-ci ne se poursuit que si aucun objet portant le nom spécifié n'existe dans le bucket, ou s'il n'existe que des versions obsolètes de l'objet dans le bucket. S'il existe une version active portant le nom spécifié, la requête échoue avec le code d'état 412 Precondition Failed.
Bonnes pratiques et pistes de réflexion
Vous pouvez utiliser plusieurs préconditions dans une même requête. Si l'une des préconditions n'est pas remplie, la requête globale échoue.
Les buckets n'ont pas de numéro de génération, bien qu'ils comportent un numéro de métagénération. Vous ne devez pas utiliser de préconditions qui spécifient un numéro de génération dans une requête de bucket.
Si vous utilisez une précondition de métagénération dans une requête d'objet, vous devez également utiliser une précondition de génération. Cela empêche la requête d'aboutir sur un objet différent qui possède par coïncidence un numéro de métagénération répondant à la précondition.
Pour les buckets qui comportent à la fois des versions d'objet actives et archivées, les requêtes d'objet ne s'appliquent pas aux versions archivées, sauf si un numéro de génération est explicitement inclus dans la requête. Cela signifie que pour une requête générale qui utilise des préconditions, la requête échoue si la version active ne satisfait pas la précondition, qu'une version archivée corresponde ou non aux préconditions.
Vous devez généralement utiliser des préconditions de génération et de métagénération au lieu de préconditions ETag. La paire que constituent les numéros de génération et de métagénération permet de garder une trace de toutes les mises à jour d'objets, y compris les modifications de métadonnées. Cela offre une garantie plus solide que celle fournie par les ETag. De plus, les numéros de génération et de métagénération sont cohérents entre les API, contrairement aux ETags.
Les préconditions ne peuvent pas être utilisées dans les importations en plusieurs parties avec l'API XML. Tenter de les utiliser entraîne une erreur
400 NotImplemented.
Coût des préconditions
De nombreuses architectures utilisant des préconditions nécessitent d'effectuer une requête de métadonnées d'objet avant la requête principale afin de déterminer le numéro de génération et/ou de métagénération actuel :
- Une requête supplémentaire implique que vous pouvez doubler la partie de réseau correspondant à la latence opérationnelle globale en ajoutant un aller-retour, ce qui peut avoir un impact important sur les opérations sensibles à la latence.
- Une requête supplémentaire entraîne une facturation et, dans la plupart des cas, des frais de mise en réseau.
Selon votre application, il existe des moyens de réduire l'impact de l'utilisation de préconditions, par exemple :
- le stockage en local des numéros de génération et de méta-génération de vos objets, ce qui vous permet de connaître déjà les bons numéros à utiliser dans votre précondition ;
- la connaissance, au niveau de l'application, des objets nouvellement créés, afin de savoir à quel moment utiliser la précondition
if-generation-match:0;
Exemple : utiliser une précondition
L'exemple suivant utilise la précondition de correspondance de génération dans une requête pour importer un objet. Pour que la requête aboutisse, il doit y avoir un objet préexistant stocké dans le bucket avec le nom spécifié, et le numéro de génération de l'objet préexistant doit correspondre au numéro fourni dans la précondition :
Ligne de commande
Utilisez le flag --if-generation-match avec la commande normale :
gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME --if-generation-match=GENERATION
Où :
GENERATIONcorrespond au numéro de génération prévu pour l'objet que vous remplacez. Par exemple,1122334455667788.OBJECT_LOCATIONcorrespond au chemin d'accès local à votre objet. Par exemple,Desktop/dog.png.DESTINATION_BUCKET_NAMEcorrespond au nom du bucket dans lequel vous importez votre objet. Par exemple,my-bucket.
API JSON
Vous devez installer et initialiser la gcloud CLI afin de générer un jeton d'accès pour l'en-tête
Authorization.Utilisez
cURLpour appeler l'API JSON avec une requêtePOSTObject :curl -X POST --data-binary @OBJECT_LOCATION \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: OBJECT_CONTENT_TYPE" \ "https://storage.googleapis.com/upload/storage/v1/b/BUCKET_NAME/o?uploadType=media&name=OBJECT_NAME"&ifGenerationMatch=GENERATION"
Où :
OBJECT_LOCATIONcorrespond au chemin d'accès local à votre objet. Par exemple,Desktop/dog.png.OBJECT_CONTENT_TYPEcorrespond au type de contenu de l'objet. Par exemple,image/png.BUCKET_NAMEcorrespond au nom du bucket dans lequel vous importez votre objet. Par exemple,my-bucket.OBJECT_NAMEcorrespond au nom que vous souhaitez attribuer à l'objet. Par exemple,dog.png.GENERATIONcorrespond au numéro de génération prévu pour l'objet que vous remplacez. Par exemple,1122334455667788.
API XML
Vous devez installer et initialiser la gcloud CLI afin de générer un jeton d'accès pour l'en-tête
Authorization.Utilisez
cURLpour appeler l'API XML avec une requêtePUTObject :curl -X PUT --data-binary @OBJECT_LOCATION \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: OBJECT_CONTENT_TYPE" \ -H "x-goog-if-generation-match: GENERATION" \ "https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME"
Où :
OBJECT_LOCATIONcorrespond au chemin d'accès local à votre objet. Par exemple,Desktop/dog.png.OBJECT_CONTENT_TYPEcorrespond au type de contenu de l'objet. Par exemple,image/png.GENERATIONcorrespond au numéro de génération prévu pour l'objet que vous remplacez. Par exemple,1122334455667788.BUCKET_NAMEcorrespond au nom du bucket dans lequel vous importez votre objet. Par exemple,my-bucket.OBJECT_NAMEcorrespond au nom que vous souhaitez attribuer à l'objet. Par exemple,dog.png.
Scénarios d'utilisation de préconditions
Les scénarios suivants explorent les conditions de concurrence et les exemples de mise en cache qui bénéficient de l'utilisation de préconditions.
Tentatives multiples d'exécution de requête
Cloud Storage est un système distribué. Étant donné que les requêtes peuvent échouer en raison des conditions de réseau ou de service, la méthode recommandée pour effectuer de nouvelles tentatives après échec consiste à utiliser un intervalle exponentiel entre les tentatives. Cependant, en raison de la nature des systèmes distribués, ces tentatives peuvent parfois entraîner un comportement surprenant.
Prenons le cas suivant : vous souhaitez supprimer un objet file.txt stocké dans l'un de vos buckets. Vous souhaitez ensuite ajouter un objet portant le même nom au bucket. Pour ce faire, vous envoyez une requête de suppression de l'objet. Cependant, en raison d'une condition de réseau, telle qu'une perte temporaire de connectivité sur un routeur intermédiaire, la requête ne parvient pas à atteindre Cloud Storage et vous ne recevez pas de réponse.
Comme vous n'avez pas reçu de réponse à la première requête de suppression de l'objet, vous en émettez une seconde, qui aboutit, et vous recevez une réponse confirmant la suppression. Une minute plus tard, vous importez un nouvel objet file.txt, et l'importation aboutit.
Une condition de concurrence survient si le routeur qui a perdu la connectivité la récupère par la suite et envoie à Cloud Storage votre requête de suppression d'origine, qui était apparemment perdue. Lorsque la demande arrive au niveau de Cloud Storage, elle aboutit car un nouvel objet file.txt est présent. Cloud Storage envoie une réponse que vous ne recevez pas, car votre client a cessé de l'écouter.
Non seulement le nouveau fichier est supprimé, contrairement à vos intentions, mais en plus, vous n'êtes pas au courant de la seconde suppression.
Le schéma suivant illustre le déroulement des événements :
Éviter la condition de concurrence
Pour éviter la situation décrite ci-dessus, vous devez d'abord obtenir les métadonnées de l'objet file.txt afin de déterminer sa génération actuelle. Vous utilisez ensuite la génération dans une précondition de correspondance de génération que vous incluez dans la requête de suppression. L'utilisation de la précondition garantit que seul l'objet portant ce numéro de génération sera supprimé, quels que soient le moment où la requête de suppression atteint Cloud Storage ou le nombre de fois où la requête de suppression associée à la précondition est envoyée. Toute tentative non souhaitée de suppression d'une autre génération de file.txt échoue avec le code de réponse 412 Precondition Failed.
Étant donné que des interruptions de réseau similaires peuvent entraîner des conditions de concurrence pour la requête d'importation qui suit votre requête de suppression, vous pouvez éviter un grand nombre de ces conditions de concurrence en utilisant la valeur 0 dans une précondition de correspondance de génération incluse dans la requête d'importation. Utiliser cette précondition garantit que les tentatives d'importation n'écrivent pas accidentellement l'objet deux fois, car elle permet à la requête d'aboutir seulement s'il n'y a pas de génération actuelle de l'objet.
Ces préconditions vous permettent de protéger vos données contre toute perte accidentelle lors de l'exécution des requêtes de suppression et d'importation. Le schéma suivant illustre ce cas de figure :
Association de métadonnées d'objets
Les données et les métadonnées d'un objet sont des entités distinctes qui, ensemble, définissent l'objet dans Cloud Storage. Comme elles existent séparément, il est possible que les données d'un objet soient modifiées lorsque vous utilisez les métadonnées de l'objet.
Considérons les cas suivants :
Vous souhaitez télécharger les métadonnées et les données d'un objet, qui doivent être extraites de Cloud Storage par le biais de deux requêtes distinctes. Vous demandez d'abord les métadonnées de l'objet, mais avant que vous ne puissiez demander les données de l'objet, un processus indépendant ou un autre utilisateur remplace l'objet. Votre requête pour les données d'objet aboutit, mais vous disposez désormais des métadonnées de l'ancien objet et des données du nouvel objet.
Vous souhaitez mettre à jour les métadonnées d'un objet. Vous devez donc récupérer les métadonnées actuelles de l'objet pour déterminer son état actuel. Avant que vous ne puissiez envoyer la requête de mise à jour des métadonnées avec les modifications souhaitées, un processus indépendant ou un autre utilisateur remplace l'objet. Votre requête de modification des métadonnées du nouvel objet aboutit quand même, mais elle est maintenant associée à des données d'objet différentes de celles que vous souhaitiez.
Éviter la condition de concurrence
Pour éviter ces situations, vous devez utiliser le numéro de génération renvoyé dans la requête initiale pour les métadonnées d'objet, puis utiliser cette valeur dans une précondition de correspondance de génération dans la deuxième requête. Cela garantit que les métadonnées correspondent bien aux données, ou que la deuxième requête échoue avec un code de réponse 412 Precondition Failed, ce qui vous permet de demander alors les métadonnées appropriées pour le nouvel objet.
Si vous craignez que les métadonnées de l'objet puissent changer entre la première et la deuxième requête, vous pouvez également copier le numéro de métagénération trouvé dans la requête initiale et l'utiliser dans une précondition de correspondance de métagénération dans la deuxième requête.
Actualisation des copies locales
Si vous disposez d'une copie locale d'un objet stocké dans Cloud Storage, vous devez souvent veiller à maintenir votre copie locale à jour par rapport à la copie stockée dans votre bucket. Toutefois, si l'objet stocké dans votre bucket ne change pas, vous ne voulez pas perdre du temps et des ressources à le télécharger à nouveau, en particulier si l'objet est volumineux.
Pour éviter les téléchargements inutiles de contenus qui sont toujours à jour, vous pouvez utiliser le numéro de génération de votre copie locale comme valeur dans une précondition de non-correspondance de génération, que vous incluez dans votre requête de téléchargement :
Si les données de votre bucket continuent de correspondre à votre copie locale, les numéros de génération correspondent, ce qui entraîne l'échec de la précondition. Par conséquent, la requête globale échoue avec une réponse
304 Not Modifiedet les données ne sont pas inutilement téléchargées.Si les données de votre bucket ont changé, les numéros de génération ne correspondent pas et la précondition aboutit. Cela signifie que la requête globale se déroule normalement et que la version mise à jour du contenu est téléchargée.
Étapes suivantes
- Apprenez-en plus sur les numéros de génération et de métagénération.
- Obtenez les métadonnées d'un objet, comme son numéro de génération.
- Découvrez la cohérence dans Cloud Storage.
- Découvrez les opérations idempotentes sous conditions qui doivent utiliser des préconditions.