In questa pagina vengono descritte le condizioni preliminari delle richieste, che puoi utilizzare per impedire l'applicazione delle richieste a una risorsa quando questa si trova in uno stato imprevisto.
Introduzione
Quando vengono utilizzate le precondizioni in una richiesta a Cloud Storage, la richiesta procede solo se la risorsa target soddisfa i criteri definiti nelle precondizioni. I controlli di precondizione assicurano che un bucket o un oggetto si trovi nello stato previsto, consentendoti di eseguire operazioni condizionali e aggiornamenti di lettura, modifica e scrittura sicuri.
Le precondizioni vengono spesso utilizzate per evitare le condizioni di gara in richieste mutate, come caricamenti, eliminazioni o aggiornamenti dei metadati. Le condizioni di gara possono verificarsi quando la stessa richiesta viene inviata ripetutamente o quando processi indipendenti tentano di modificare la stessa risorsa. Per ulteriori informazioni, vedi Esempi di condizioni di gara e danneggiamento dei dati. Le precondizioni vengono spesso utilizzate quando si recuperano metadati e dati degli oggetti nelle richieste successive, per garantire che l'oggetto non sia cambiato nell'intervallo di tempo tra le due richieste.
Criteri di precondizione
Cloud Storage supporta l'uso di diverse proprietà immutabili delle risorse in condizioni preliminari:
- Numeri di generazione e metagenerazione
- ETags
- La data
Last-Modified
(disponibile solo quando si ottengono dati o metadati dell'oggetto utilizzando l'API XML)
Nella tabella seguente sono elencate le condizioni preliminari supportate dall'API JSON e dall'API XML:
API JSON | API XML | Descrizione |
---|---|---|
ifGenerationMatch parametro di query |
Intestazione x-goog-if-generation-match |
La richiesta procede se il valore generation della risorsa di destinazione corrisponde al valore utilizzato nella condizione preliminare. Se i valori non corrispondono, la richiesta non riesce e restituisce una risposta 412 Precondition Failed . |
ifMetagenerationMatch parametro di query |
Intestazione x-goog-if-metageneration-match |
La richiesta procede se il valore metageneration della risorsa di destinazione corrisponde al valore utilizzato nella condizione preliminare. Se i valori non corrispondono, la richiesta non riesce e restituisce una risposta 412 Precondition Failed . |
ifGenerationNotMatch parametro di query |
N/A | La richiesta procede se il valore generation della risorsa di destinazione non corrisponde al valore utilizzato nella condizione preliminare. Se i valori corrispondono, la richiesta non riesce e restituisce una risposta 304 Not Modified . |
ifMetagenerationNotMatch parametro di query |
N/A | La richiesta procede se il valore metageneration della risorsa di destinazione non corrisponde al valore utilizzato nella condizione preliminare. Se i valori corrispondono, la richiesta non riesce e restituisce una risposta 304 Not Modified . |
Intestazione If-Match |
Intestazione If-Match |
Applicabile per le richieste che recuperano dati. La richiesta procede se il valore ETag della risorsa di destinazione corrisponde al valore utilizzato nella condizione preliminare. Se i valori non corrispondono, la richiesta non riesce e restituisce una risposta 412 Precondition Failed . |
Intestazione If-None-Match |
Intestazione If-None-Match |
Applicabile per le richieste che recuperano dati. La richiesta procede se il valore ETag della risorsa di destinazione non corrisponde al valore utilizzato nella condizione preliminare. Se i valori corrispondono, la richiesta non riesce e restituisce una risposta 304 Not Modified . |
N/A | Intestazione If-Modified-Since |
La richiesta procede se la risorsa di destinazione ha una data Last-Modified successiva al valore utilizzato nella condizione preliminare. Se la risorsa di destinazione non soddisfa questa condizione preliminare, la richiesta non va a buon fine e viene inviata una risposta 304 Not Modified . |
N/A | Intestazione If-Unmodified-Since |
La richiesta procede se la risorsa di destinazione ha una data Last-Modified precedente o uguale al valore utilizzato nella precondizione. Se la risorsa di destinazione non soddisfa questa condizione preliminare, la richiesta non va a buon fine e viene inviata una risposta 412 Precondition Failed . |
Condizioni preliminari per la composizione di oggetti
Quando esegui la composizione degli oggetti, sia l'API JSON sia l'API XML supportano quanto segue:
Le precondizioni di generazione e corrispondenza della metagenerazione per l'oggetto di destinazione.
La precondizione per la corrispondenza di generazione per ogni oggetto di origine. L'utilizzo di questa condizione preliminare impedisce l'utilizzo di componenti errati nel caso in cui un processo indipendente sovrascriva uno dei componenti previsti della composizione. Se utilizzi le precondizioni e si verifica una sovrascrittura, le operazioni
compose
non riescono e una risposta412 Precondition Failed
.
Condizioni preliminari per la copia degli oggetti
Durante la copia o la riscrittura di un oggetto all'interno di Cloud Storage, sia l'API JSON sia l'API XML supportano l'utilizzo di precondizioni standard per l'oggetto di destinazione. Ogni API offre un supporto aggiuntivo di precondizione per gli oggetti di origine:
L'API JSON supporta le precondizioni di generazione e metagenerazione per l'oggetto di origine, che vengono specificate utilizzando parametri di ricerca preceduti dal prefisso
ifSource
.Tutte le condizioni preliminari supportate dall'API XML possono essere utilizzate per l'oggetto di origine. Queste precondizioni sono specificate nelle intestazioni con prefisso
x-goog-copy-source-
.
Il valore 0
in una precondizione per la corrispondenza di generazione
La precondizione per la corrispondenza di generazione accetta il valore 0
come caso speciale. Quando in una richiesta viene inclusa una precondizione per la corrispondenza di generazione con valore 0
, la richiesta procede solo se nel bucket non esiste alcun oggetto con il nome specificato o se sono presenti solo versioni non correnti dell'oggetto nel bucket. Se esiste una versione live con il nome specificato, la richiesta non riesce e viene restituito un codice di stato 412 Precondition Failed
.
Best practice e considerazioni
Puoi utilizzare più precondizioni in una singola richiesta. Se una qualsiasi delle condizioni preliminari non viene soddisfatta, la richiesta complessiva non va a buon fine.
I bucket non hanno un numero di generazione, anche se hanno un numero di metagenerazione. Non utilizzare condizioni preliminari che specificano un numero di generazione in una richiesta di bucket.
Se utilizzi una precondizione di metagenerazione in una richiesta di oggetto, devi utilizzare sempre anche una precondizione di generazione. Questo impedisce che la richiesta abbia esito positivo su un oggetto diverso che ha accidentalmente un numero di metagenerazione che supera la precondizione.
Per i bucket che hanno versioni dell'oggetto attive e non correnti, le richieste degli oggetti non si applicano alle versioni non correnti, a meno che un numero di generazione non sia incluso esplicitamente nella richiesta. Ciò significa che, per una richiesta generale che utilizza le precondizioni, la richiesta non va a buon fine se la versione live non soddisfa la condizione preliminare, indipendentemente dal fatto che una versione non corrente soddisfa o meno le precondizioni.
In genere, è consigliabile utilizzare le precondizioni di generazione e metagenerazione anziché le precondizioni ETag. Insieme, i numeri di generazione e metagenerazione tengono traccia di tutti gli aggiornamenti degli oggetti, comprese le modifiche ai metadati, garantendo una maggiore garanzia rispetto agli ETag. Inoltre, i numeri di generazione e metagenerazione sono coerenti tra le API, mentre gli ETag no.
Le condizioni preliminari non possono essere utilizzate nei caricamenti multiparte dell'API XML. Se provi a farlo, verrà visualizzato un errore
400 NotImplemented
.
Costo delle precondizioni
Molte architetture che utilizzano precondizioni richiedono di effettuare una richiesta di metadati dell'oggetto prima della richiesta principale, al fine di determinare il numero di generazione e/o metagenerazione attuale:
- Una richiesta aggiuntiva significa che puoi raddoppiare la porzione di rete della latenza complessiva delle operazioni aggiungendo un round trip aggiuntivo, che potrebbe essere un fattore importante per le operazioni sensibili alla latenza.
- Una richiesta aggiuntiva comporta un costo operativo e, nella maggior parte dei casi, un costo di rete.
A seconda dell'applicazione, esistono modi per ridurre l'impatto dell'utilizzo delle precondizioni, ad esempio:
- Archiviazione dei numeri di generazione e metagenerazione degli oggetti localmente in modo da conoscere già i numeri corretti da utilizzare nella condizione preliminare.
- Conoscere l'applicazione degli oggetti appena creati, in modo da sapere già quando utilizzare la condizione preliminare
if-generation-match:0
.
Esempio: utilizzo di una condizione preliminare
L'esempio seguente utilizza la precondizione per la corrispondenza di generazione in una richiesta di caricamento di un oggetto. Affinché la richiesta prosegua, deve essere presente un oggetto preesistente archiviato nel bucket con il nome specificato e il numero di generazione dell'oggetto preesistente deve corrispondere al numero fornito nella condizione preliminare:
Riga di comando
Utilizza il flag --if-generation-match
insieme al comando normale:
gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME --if-generation-match=GENERATION
Dove:
GENERATION
è il numero di generazione previsto dell'oggetto che stai sostituendo. Ad esempio,1122334455667788
.OBJECT_LOCATION
è il percorso locale dell'oggetto. Ad esempio,Desktop/dog.png
.DESTINATION_BUCKET_NAME
è il nome del bucket in cui stai caricando l'oggetto. Ad esempio,my-bucket
.
API JSON
Installa e inizializzatogcloud CLI per generare un token di accesso per l'intestazione
Authorization
.In alternativa, puoi creare un token di accesso utilizzando OAuth 2.0 Playground e includerlo nell'intestazione
Authorization
.Usa
cURL
per chiamare l'API JSON con una richiesta OggettoPOST
: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"
Dove:
OBJECT_LOCATION
è il percorso locale dell'oggetto. Ad esempio,Desktop/dog.png
.OBJECT_CONTENT_TYPE
è il tipo di contenuto dell'oggetto. Ad esempio,image/png
.BUCKET_NAME
è il nome del bucket in cui carichi l'oggetto. Ad esempio,my-bucket
.OBJECT_NAME
è il nome che vuoi assegnare all'oggetto. Ad esempio,dog.png
.GENERATION
è il numero di generazione previsto dell'oggetto che stai sostituendo. Ad esempio,1122334455667788
.
API XML
Installa e inizializzatogcloud CLI per generare un token di accesso per l'intestazione
Authorization
.In alternativa, puoi creare un token di accesso utilizzando OAuth 2.0 Playground e includerlo nell'intestazione
Authorization
.Utilizza
cURL
per chiamare l'API XML con una richiesta OggettoPUT
: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"
Dove:
OBJECT_LOCATION
è il percorso locale dell'oggetto. Ad esempio,Desktop/dog.png
.OBJECT_CONTENT_TYPE
è il tipo di contenuto dell'oggetto. Ad esempio,image/png
.GENERATION
è il numero di generazione previsto dell'oggetto che stai sostituendo. Ad esempio,1122334455667788
.BUCKET_NAME
è il nome del bucket in cui carichi l'oggetto. Ad esempio,my-bucket
.OBJECT_NAME
è il nome che vuoi assegnare all'oggetto. Ad esempio,dog.png
.
Scenari di utilizzo delle condizioni preliminari
Gli scenari seguenti esplorano le condizioni di gara ed esempi di memorizzazione nella cache che sfruttano l'uso di precondizioni.
Più tentativi di richiesta
Cloud Storage è un sistema distribuito. Poiché le richieste possono non riuscire a causa delle condizioni di rete o del servizio, il modo consigliato per riprovare gli errori è mediante il backoff esponenziale. Tuttavia, a causa della natura dei sistemi distribuiti, a volte questi nuovi tentativi possono causare comportamenti sorprendenti.
Considera il seguente caso: vuoi eliminare un oggetto, file.txt
, archiviato in
uno dei tuoi bucket. In seguito vorrai aggiungere al bucket un nuovo oggetto con lo stesso nome. A questo scopo, devi inviare una richiesta di eliminazione
per eliminare l'oggetto. Tuttavia, una condizione di rete, come un router intermedio che perde temporaneamente la connettività, impedisce alla richiesta di raggiungere Cloud Storage e non ricevi risposta.
Poiché non hai ricevuto una risposta alla prima richiesta, emetti una seconda
richiesta di eliminazione per l'oggetto, che va a buon fine, e riceverai una risposta
che conferma l'eliminazione. Un minuto dopo, carichi un nuovo file.txt
e il caricamento
è riuscito.
Si verifica una race condition se il router che ha perso la connettività successivamente lo recupera e invia la richiesta di eliminazione originale, apparentemente persa, in avanti a Cloud Storage. Quando la richiesta arriva a Cloud Storage, riuscita perché è presente un nuovo file.txt
. Cloud Storage invia una risposta che non ricevi perché il client ha smesso di ascoltarla.
Il nuovo file non viene solo eliminato, contrariamente alle tue intenzioni, ma non sai nemmeno che si è verificata la seconda eliminazione.
Il seguente diagramma mostra cosa è successo:
Prevenzione della race condition
Per evitare che si verifichi la situazione precedente, devi iniziare a recuperare i metadati per file.txt
per determinarne la generazione attuale. Potrai quindi utilizzare la generazione in una precondizione di corrispondenza di generazione che includi nella richiesta di eliminazione. La precondizione garantisce che venga eliminato solo l'oggetto con lo specifico numero di generazione, indipendentemente da quando la richiesta di eliminazione raggiunge Cloud Storage o dal numero di volte in cui viene inviata la richiesta di eliminazione con la precondizione. Eventuali tentativi involontari di eliminare una generazione diversa
di file.txt
non vanno a buon fine con il codice di risposta 412 Precondition Failed
.
Poiché interruzioni di rete simili potrebbero causare condizioni di gara per la richiesta di caricamento
successiva alla richiesta di eliminazione, puoi evitarne molte
utilizzando il valore 0
in una precondizione per la corrispondenza di generazione
inclusa nella richiesta di caricamento. L'utilizzo di questa condizione preliminare garantisce che i nuovi tentativi di caricamento non scrivano accidentalmente l'oggetto due volte, perché la condizione preliminare consente alla richiesta di procedere solo se non esistono generazioni attuali dell'oggetto.
Con queste condizioni preliminari, proteggi i tuoi dati dalla perdita accidentale durante l'esecuzione delle richieste di eliminazione e caricamento. Questo è possibile vedere nel seguente diagramma:
Associazione di metadati degli oggetti
I dati e i metadati di un oggetto sono entità separate che definiscono l'oggetto in Cloud Storage. Poiché esistono separatamente, i dati dell'oggetto possono cambiare mentre lavori con i metadati dell'oggetto.
Considera i seguenti casi:
Vuoi scaricare i metadati e i dati di un oggetto, che devono essere recuperati da Cloud Storage in due richieste separate. Devi prima richiedere i metadati dell'oggetto, ma prima di poter richiedere i dati dell'oggetto, un processo o un utente indipendente sostituisce l'oggetto. La tua richiesta dei dati dell'oggetto è ancora riuscita, ma ora hai i metadati dell'oggetto precedente e i dati del nuovo oggetto.
Vuoi aggiornare i metadati per un oggetto, in modo da recuperare i metadati attuali dell'oggetto per determinarne lo stato attuale. Prima di poter inviare la richiesta di aggiornamento dei metadati con le modifiche desiderate, l'oggetto viene sostituito da un processo o un utente indipendente. La tua richiesta di modifica dei metadati per il nuovo oggetto è ancora riuscita, ma ora è associata a dati dell'oggetto diversi da quelli previsti.
Prevenzione della race condition
Per evitare che si verifichino queste situazioni, devi utilizzare il numero di generazione restituito nella richiesta iniziale per i metadati degli oggetti, quindi utilizzare questo valore in una precondizione per la corrispondenza di generazione nella seconda richiesta. In questo modo si garantisce che i metadati corrispondano correttamente ai dati o che la seconda richiesta non abbia esito positivo con un codice di risposta 412 Precondition Failed
, consentendo di richiedere i metadati corretti per il nuovo oggetto.
Se temi che i metadati dell'oggetto possano cambiare tra la prima e la seconda richiesta, puoi anche copiare il numero di metagenerazione trovato nella richiesta iniziale e utilizzarlo in una precondizione di corrispondenza della metagenerazione nella seconda richiesta.
Aggiornamento della copia locale
Se disponi di una copia locale di un oggetto archiviata in Cloud Storage, spesso vuoi che la copia locale sia aggiornata con la copia archiviata nel bucket. Tuttavia, se l'oggetto archiviato nel bucket non cambia, non è consigliabile sprecare tempo e risorse per scaricarlo di nuovo, soprattutto se l'oggetto è di grandi dimensioni.
Per evitare download inutili di contenuti ancora attuali, puoi utilizzare il numero di generazione della copia locale come valore in una precondizione di generazione non corrispondente, che includi nella richiesta di download:
Se i dati nel bucket continuano a corrispondere alla copia locale, i numeri di generazione corrispondono, causando il mancato superamento della condizione preliminare. Di conseguenza, la richiesta complessiva non va a buon fine e restituisce una risposta
304 Not Modified
e i dati non vengono scaricati inutilmente.Se i dati nel bucket sono cambiati, i numeri di generazione non corrispondono e la condizione preliminare viene soddisfatta. Ciò significa che la richiesta complessiva procede normalmente e scarica la versione aggiornata dei contenuti.
Passaggi successivi
- Scopri di più sui numeri di generazione e metagenerazione.
- Recuperare i metadati per un oggetto, ad esempio il numero di generazione.
- Scopri di più sulla coerenza in Cloud Storage.
- Scopri di più sulle operazioni idempotenti condizionate che dovrebbero utilizzare le precondizioni.