Cette page traite des conditions préalables 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.
Présentation
Lorsque des conditions préalables 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 conditions préalables. Les vérifications de conditions préalables 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 conditions préalables sont souvent utilisées pour éviter les conditions de concurrence dans les requêtes de mutation, par exemple pour 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 la section Exemples de conditions de concurrence et de corruption de données. Les conditions préalables sont également utilisées lors de la récupération des métadonnées et des données d'objet dans les requêtes successives, pour garantir que l'objet n'a pas changé entre les deux requêtes.
Critères de condition préalable
Cloud Storage accepte l'utilisation de plusieurs propriétés de ressource immuable différentes dans des conditions préalables :
- 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 d'objet ou de métadonnées à l'aide de l'API XML)
Le tableau suivant répertorie les conditions préalables 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 generation de la ressource cible correspond à la valeur utilisée dans la condition préalable. 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 metageneration de la ressource cible correspond à la valeur utilisée dans la condition préalable. 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 generation de la ressource cible ne correspond pas à la valeur utilisée dans la condition préalable. 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 metageneration de la ressource cible ne correspond pas à la valeur utilisée dans la condition préalable. 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 ETag de la ressource cible correspond à la valeur utilisée dans la condition préalable. 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 ETag de la ressource cible ne correspond pas à la valeur utilisée dans la condition préalable. 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 condition préalable. Si la ressource cible ne remplit pas cette condition préalable, la requête échoue avec une réponse 304 Not Modified . |
N/A | En-tête If-Unmodified-Since |
La requête continue si la ressource cible a une date Last-Modified antérieure ou égale à la valeur utilisée dans la condition préalable. Si la ressource cible ne remplit pas cette condition préalable, la requête échoue avec une réponse 412 Precondition Failed . |
Conditions préalables de composition d'objets
Lors de la composition d'objets, l'API JSON et l'API XML sont compatibles avec les éléments suivants :
Les conditions préalables de correspondance de génération et de métagénération pour l'objet de destination.
La condition préalable de correspondance de génération pour chaque objet source. L'utilisation de cette condition préalable 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 conditions préalables et que ce type d'écrasement se produit, les opérations
compose
échouent avec une réponse412 Precondition Failed
.
Conditions préalables 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 sont compatibles avec l'utilisation de conditions préalables standards pour l'objet de destination. Chaque API accepte des conditions préalables supplémentaires pour les objets sources :
L'API JSON accepte les conditions préalables de génération et de métagénération pour l'objet source, qui sont spécifiées à l'aide de paramètres de requête précédés de
ifSource
.Toutes les conditions préalables acceptées par l'API XML peuvent être utilisées pour l'objet source. Ces conditions préalables sont spécifiées dans les en-têtes précédés du préfixe
x-goog-copy-source-
.
Valeur 0
dans une condition préalable de correspondance de génération
La condition préalable de correspondance de génération accepte la valeur 0
comme cas particulier. Lorsqu'une condition préalable 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 conditions préalables dans une même requête. Si l'une des conditions préalables 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 conditions préalables qui spécifient un numéro de génération dans une requête de bucket.
Si vous utilisez une condition préalable de métagénération dans une requête d'objet, vous devez également utiliser une condition préalable 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 condition préalable.
Pour les buckets qui ont à 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 conditions préalables, la requête échoue si la version active ne satisfait pas la condition préalable, qu'une version archivée corresponde ou non aux conditions préalables.
Vous devez généralement utiliser des conditions préalables de génération et de métagénération au lieu de conditions préalables ETag. La paire que constituent les numéros de génération et de metagénération permet de garder une trace de toutes les mises à jour d'objets, y compris les modifications de métadonnées, fournissant ainsi une garantie plus solide que celle des 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 conditions préalables ne peuvent pas être utilisées dans les importations en plusieurs parties avec l'API XML. Toute tentative de désactivation entraîne une erreur
400 NotImplemented
.
Coût des conditions préalables
De nombreuses architectures utilisant des conditions préalables 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 signifie 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 les impacts de l'utilisation de conditions préalables, par exemple :
- le stockage en local des numéros de génération et de méta-génération de vos objets de sorte que vous connaissiez déjà les bons numéros à utiliser dans votre condition préalable ;
- la connaissance, au niveau de l'application, des objets nouvellement créés, afin de savoir à quel moment utiliser la condition préalable
if-generation-match:0
;
Exemple : utiliser une condition préalable
L'exemple suivant utilise la condition préalable 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 condition préalable :
Ligne de commande
Utilisez l'option --if-generation-match
avec la commande normale :
gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME --if-generation-match=GENERATION
Où :
GENERATION
correspond au numéro de génération prévu de l'objet que vous remplacez. Exemple :1122334455667788
OBJECT_LOCATION
correspond au chemin d'accès local à votre objet. Par exemple,Desktop/dog.png
.DESTINATION_BUCKET_NAME
correspond au nom du bucket dans lequel vous importez votre objet. Exemple :my-bucket
API JSON
Vous devez installer et initialiser gcloud CLI afin de générer un jeton d'accès pour l'en-tête
Authorization
.Vous pouvez également créer un jeton d'accès à l'aide d'OAuth 2.0 Playground et l'inclure dans l'en-tête
Authorization
.Exécutez
cURL
pour appeler l'API JSON avec une requête d'objetPOST
: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_LOCATION
correspond au chemin d'accès local à votre objet. Exemple :Desktop/dog.png
OBJECT_CONTENT_TYPE
correspond au type de contenu de l'objet. Exemple :image/png
BUCKET_NAME
correspond au nom du bucket dans lequel vous importez votre objet. Exemple :my-bucket
OBJECT_NAME
correspond au nom que vous souhaitez attribuer à l'objet. Exemple :dog.png
GENERATION
correspond au numéro de génération prévu de l'objet que vous remplacez. Exemple :1122334455667788
API XML
Vous devez installer et initialiser gcloud CLI afin de générer un jeton d'accès pour l'en-tête
Authorization
.Vous pouvez également créer un jeton d'accès à l'aide d'OAuth 2.0 Playground et l'inclure dans l'en-tête
Authorization
.Utilisez
cURL
pour appeler l'API XML avec une requête d'objetPUT
: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_LOCATION
correspond au chemin d'accès local à votre objet. Exemple :Desktop/dog.png
OBJECT_CONTENT_TYPE
correspond au type de contenu de l'objet. Exemple :image/png
GENERATION
correspond au numéro de génération prévu de l'objet que vous remplacez. Exemple :1122334455667788
BUCKET_NAME
correspond au nom du bucket dans lequel vous importez votre objet. Exemple :my-bucket
OBJECT_NAME
correspond au nom que vous souhaitez attribuer à l'objet. Exemple :dog.png
Scénarios d'utilisation de conditions préalables
Les scénarios suivants explorent les conditions de concurrence et les exemples de mise en cache qui bénéficient de l'utilisation de conditions préalables.
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 aboutir à 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 émettez une demande de suppression pour supprimer l'objet. Cependant, en raison d'une condition de réseau, telle qu'un routeur intermédiaire qui perd temporairement sa connectivité, 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 nouveau fichier 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, apparemment perdue. Lorsque la demande arrive sur Cloud Storage, elle aboutit car un nouveau 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 vous n'êtes pas non plus 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 ci-dessus, vous devez d'abord obtenir les métadonnées du fichier file.txt
afin de déterminer sa génération actuelle. Vous utilisez ensuite la génération dans une condition préalable de correspondance de génération que vous incluez dans la requête de suppression. L'utilisation de la condition préalable garantit que seul l'objet portant ce numéro de génération est supprimé, quel que soit 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 condition préalable est envoyée. Toute tentative involontaire 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 en éviter beaucoup en utilisant la valeur 0
dans une condition préalable de correspondance de génération incluse dans la requête d'importation. Ceci 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érations actuelles de l'objet.
Ces conditions préalables 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 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, par exemple, 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 en deux requêtes distinctes. Vous demandez d'abord les métadonnées de l'objet, mais avant que vous puissiez demander les données de l'objet, un processus ou un utilisateur indépendant 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 de pouvoir envoyer la requête de mise à jour des métadonnées avec les modifications souhaitées, un processus ou un utilisateur indépendant 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 condition préalable 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 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 condition préalable 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 condition préalable 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 condition préalable. Par conséquent, la requête globale échoue avec une réponse
304 Not Modified
et 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 condition préalable aboutit. Cela signifie que la requête globale se déroule normalement et télécharge la version mise à jour du contenu.
Étape suivante
- En savoir 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 conditions préalables.