Questa pagina illustra i precondizioni delle richieste, che vengono utilizzati per impedire l'applicazione delle richieste a una risorsa quando questa è in uno stato imprevisto.
Introduzione
Quando i prerequisiti vengono utilizzati in una richiesta a Cloud Storage, la richiesta procede solo se la risorsa di destinazione soddisfa i criteri definiti nei prerequisiti. I controlli dei prerequisiti assicurano che un bucket o un oggetto sia nello stato previsto, consentendo di eseguire aggiornamenti di lettura, modifica e scrittura sicuri e operazioni condizionali.
Le condizioni preliminari vengono spesso utilizzate per evitare le condizioni di gara nelle richieste con mutazioni, 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 ciascuno di modificare la stessa risorsa. Per ulteriori informazioni, consulta Esempi di condizioni di gara e corruzione dei dati. I prerequisiti vengono spesso utilizzati anche per recuperare i metadati e i dati degli oggetti nelle richieste successive, per assicurarsi che l'oggetto non sia cambiato nel tempo tra le due richieste.
Criteri di precondizione
Cloud Storage supporta l'utilizzo di diverse proprietà immutabili delle risorse nei prerequisiti:
- Numeri di generazione e metagenerazione
- ETags
- La data
Last-Modified
(disponibile solo quando si ottengono i dati o i metadati degli oggetti utilizzando l'API XML)
Nella tabella seguente sono elencati i prerequisiti supportati dall'API JSON e dall'API XML:
API JSON | API XML | Descrizione |
---|---|---|
Parametro di query ifGenerationMatch |
Intestazione x-goog-if-generation-match |
La richiesta procede se generation della risorsa di destinazione corrisponde al valore utilizzato nel precondizionale. Se i valori non corrispondono, la richiesta non va a buon fine e viene restituita una risposta 412 Precondition Failed . |
Parametro di query ifMetagenerationMatch |
Intestazione x-goog-if-metageneration-match |
La richiesta procede se metageneration della risorsa di destinazione corrisponde al valore utilizzato nel precondizionale. Se i valori non corrispondono, la richiesta non va a buon fine e viene restituita una risposta 412 Precondition Failed . |
Parametro di query ifGenerationNotMatch |
N/D | La richiesta procede se generation della risorsa di destinazione non corrisponde al valore utilizzato nel precondizionale. Se i valori corrispondono, la richiesta non va a buon fine con una risposta 304 Not Modified . |
Parametro di query ifMetagenerationNotMatch |
N/D | La richiesta procede se metageneration della risorsa di destinazione non corrisponde al valore utilizzato nel precondizionale. Se i valori corrispondono, la richiesta non va a buon fine con una risposta 304 Not Modified . |
Intestazione If-Match |
Intestazione If-Match |
Applicabile alle richieste che recuperano i dati. La richiesta procede se ETag della risorsa di destinazione corrisponde al valore utilizzato nel precondizionale. Se i valori non corrispondono, la richiesta non va a buon fine e viene restituita una risposta 412 Precondition Failed . |
Intestazione If-None-Match |
Intestazione If-None-Match |
Applicabile alle richieste che recuperano i dati. La richiesta procede se ETag della risorsa di destinazione non corrisponde al valore utilizzato nel precondizionale. Se i valori corrispondono, la richiesta non va a buon fine con una risposta 304 Not Modified . |
N/D | Intestazione If-Modified-Since |
La richiesta procede se la risorsa di destinazione ha una data Last-Modified successiva al valore utilizzato nel precondizionale. Se la risorsa di destinazione non soddisfa questo prerequisito, la richiesta non va a buon fine e viene restituita una risposta 304 Not Modified . |
N/D | Intestazione If-Unmodified-Since |
La richiesta procede se la risorsa di destinazione ha una data Last-Modified precedente o uguale al valore utilizzato nel prerequisito. Se la risorsa di destinazione non soddisfa questo prerequisito, la richiesta non va a buon fine e viene restituita una risposta 412 Precondition Failed . |
Precondizioni della composizione dell'oggetto
Quando esegui la composizione di oggetti, sia l'API JSON sia l'API XML supportano quanto segue:
Le precondizioni di corrispondenza alla generazione e alla metagenerazione per l'oggetto di destinazione.
La precondizione di corrispondenza alla generazione per ogni oggetto di origine. L'utilizzo di questo prerequisito impedisce l'utilizzo di componenti errati nel caso in cui un processo indipendente sovrascriva uno dei componenti previsti della composizione. Se utilizzi i prerequisiti e si verifica una sovrascrittura di questo tipo, le operazioni
compose
non vanno a buon fine con una risposta412 Precondition Failed
.
Precondizioni per la copia degli oggetti
Quando copi o riscrivi un oggetto in Cloud Storage, sia l'API JSON sia l'API XML supportano l'utilizzo di prerequisiti standard per l'oggetto di destinazione. Ogni API supporta un'ulteriore precondizione per gli oggetti di origine:
L'API JSON supporta i prerequisiti per la generazione e la metagenerazione per l'oggetto source, che vengono specificati utilizzando parametri di ricerca con prefisso
ifSource
.Per l'oggetto di origine è possibile utilizzare tutti i prerequisiti supportati dall'API XML. Questi prerequisiti sono specificati nelle intestazioni con prefisso
x-goog-copy-source-
.
Il valore 0
in un prerequisito di corrispondenza alla generazione
La precondizione di corrispondenza alla generazione accetta il valore 0
come caso speciale. Quando
in una richiesta è incluso un prerequisito di corrispondenza alla generazione con un valore di 0
,
la richiesta procede solo se nel
bucket non esiste alcun oggetto con il nome specificato o se nel
bucket sono presenti solo versioni non correnti dell'oggetto. Se esiste una versione pubblicata con il nome specificato, la richiesta non va a buon fine con un codice stato 412 Precondition Failed
.
Best practice e considerazioni
Puoi utilizzare più prerequisiti in una singola richiesta. Se una delle precondizioni non è soddisfatta, la richiesta complessiva non va a buon fine.
I bucket non hanno un numero di generazione, ma hanno un numero di metagenerazione. Non devi utilizzare prerequisiti che specificano un numero di generazione in una richiesta del bucket.
Se utilizzi un precondizione di metagenerazione in una richiesta di oggetti, devi sempre utilizzare anche un precondizione di generazione. In questo modo, la richiesta non andrà a buon fine su un altro oggetto che per coincidenza ha un numero di metagenerazione che supera la condizione preliminare.
Per i bucket che contengono sia versioni degli oggetti attive che non correnti, le richieste di 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 prerequisiti, la richiesta non va a buon fine se la versione pubblicata non corrisponde al prerequisito, indipendentemente dal fatto che una versione non corrente corrisponda o meno ai prerequisiti.
In genere, dovresti utilizzare i prerequisiti di generazione e metagenerazione anziché quelli ETag. I numeri di generazione e metagenerazione monitorano insieme tutti gli aggiornamenti degli oggetti, incluse le modifiche ai metadati, offrendo una garanzia più solida rispetto agli ETag. Inoltre, i numeri di generazione e metagenerazione sono coerenti tra le API, mentre gli ETag non lo sono.
I prerequisiti non possono essere utilizzati nei caricamenti multiparte dell'API XML. Il tentativo di farlo genera un errore
400 NotImplemented
.
Costo dei prerequisiti
Molte architetture che utilizzano i prerequisiti richiedono di effettuare una richiesta di metadati dell'oggetto prima della richiesta principale per determinare il numero di generazione e/o metagenerazione corrente:
- Una richiesta aggiuntiva significa che puoi raddoppiare la parte di rete della latenza complessiva dell'operazione aggiungendo un altro viaggio di andata e ritorno, che può essere un fattore importante nelle operazioni sensibili alla latenza.
- Una richiesta aggiuntiva comporta un costo di operazione 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:
- Memorizza localmente i numeri di generazione e metagenerazione degli oggetti in modo da conoscere già i numeri corretti da utilizzare nel precondizionatore.
- Avere conoscenza dell'applicazione degli oggetti appena creati, in modo da sapere già quando utilizzare la precondizione
if-generation-match:0
.
Esempio: utilizzo di un precondizione
L'esempio seguente utilizza la precondizione di corrispondenza alla generazione in una richiesta per caricare un oggetto. Affinché la richiesta venga eseguita, nel bucket deve essere memorizzato un oggetto preesistente con il nome specificato e il numero di generazione dell'oggetto preesistente deve corrispondere al numero fornito nel prerequisito:
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 carichi l'oggetto. Ad esempio,my-bucket
.
API JSON
Avere installato e inizializzatogcloud CLI, che consente di generare un token di accesso per l'intestazione
Authorization
.Utilizza
cURL
per chiamare l'API JSON con una richiesta diPOST
oggetto: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 contenuti dell'oggetto. Ad esempio,image/png
.BUCKET_NAME
è il nome del bucket in cui stai caricando 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
Avere installato e inizializzatogcloud CLI, che consente di generare un token di accesso per l'intestazione
Authorization
.Utilizza
cURL
per chiamare l'API XML con una richiesta diPUT
Object: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 contenuti 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 stai caricando l'oggetto. Ad esempio,my-bucket
.OBJECT_NAME
è il nome che vuoi assegnare all'oggetto. Ad esempio,dog.png
.
Scenari per l'utilizzo delle precondizioni
Gli scenari riportati di seguito illustrano le condizioni di gara e gli esempi di memorizzazione nella cache che beneficiano dell'utilizzo delle precondizioni.
Nuovi tentativi di richiesta multipli
Cloud Storage è un sistema distribuito. Poiché le richieste possono non riuscire a causa di condizioni della rete o del servizio, il modo consigliato per riprovare in caso di errori è con il backoff esponenziale. Tuttavia, a causa della natura dei sistemi distribuiti, a volte questi nuovi tentativi possono causare comportamenti inaspettati.
Considera il seguente caso: vuoi eliminare un oggetto, file.txt
, archiviato in uno dei tuoi bucket. Successivamente, vuoi aggiungere un nuovo oggetto con lo stesso nome al bucket. Per farlo, emetti una richiesta di eliminazione per eliminare l'oggetto. Tuttavia, una condizione della rete, ad esempio la perdita temporanea della connettività di un router intermedio, impedisce alla richiesta di raggiungere Cloud Storage e non ricevi una risposta.
Poiché non hai ricevuto una risposta alla prima richiesta, ne invii una seconda per l'eliminazione dell'oggetto, che va a buon fine e ricevi una risposta che conferma l'eliminazione. Un minuto dopo, carichi un nuovo file.txt
e il caricamento va a buon fine.
Si verifica una race condition se il router che ha perso la connettività la recupera successivamente e invia la richiesta di eliminazione originale, apparentemente persa, a Cloud Storage. Quando la richiesta arriva in Cloud Storage, viene completata perché è presente un nuovo file.txt
. Cloud Storage invia una risposta che non ricevi perché il client ha smesso di ascoltarla.
Non solo il nuovo file viene eliminato, contrariamente alle tue intenzioni, ma non sei a conoscenza della seconda eliminazione.
Il seguente diagramma mostra cosa è successo:
Evitare la race condition
Per evitare che si verifichi la situazione descritta sopra, devi iniziare recuperando i metadati di file.txt
per determinare la sua generazione attuale. Poi
utilizza la generazione in un precondizione di corrispondenza alla generazione che includi come parte
della richiesta di eliminazione. Il prerequisito garantisce che venga eliminato solo l'oggetto con quel numero di generazione specifico, indipendentemente dal momento in cui la richiesta di eliminazione raggiunge Cloud Storage o dal numero di volte in cui viene inviata la richiesta di eliminazione con il prerequisito. Eventuali tentativi involontari di eliminare una generazione diversa di file.txt
non andranno a buon fine con il codice di risposta 412 Precondition Failed
.
Poiché interruzioni della rete simili potrebbero causare condizioni di gara per la richiesta di caricamento che ha seguito la richiesta di eliminazione, puoi evitare molte di queste condizioni di gara utilizzando il valore 0
in una precondizione di corrispondenza alla generazione inclusa nella richiesta di caricamento. L'utilizzo di questo prerequisito garantisce che i tentativi di caricamento non scrivano accidentalmente l'oggetto due volte, perché il prerequisito consente alla richiesta di procedere solo se non sono presenti generazioni correnti dell'oggetto.
Con questi prerequisiti, proteggi i tuoi dati da una perdita accidentale quando esegui le richieste di eliminazione e caricamento. Come mostrato nel seguente diagramma:
Associazione dei metadati degli oggetti
I dati e i metadati di un oggetto sono entità distinte che insieme definiscono l'oggetto in Cloud Storage. Poiché esistono separatamente, è possibile che i dati dell'oggetto cambino 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 distinte. Richiedi prima i metadati dell'oggetto, ma prima che tu possa richiedere i dati dell'oggetto, un utente o un processo indipendente sostituisce l'oggetto. La tua richiesta per i dati dell'oggetto continua a dare esito positivo, ma ora hai i metadati dell'oggetto precedente e i dati del nuovo oggetto.
Vuoi aggiornare i metadati di un oggetto, quindi recuperi i metadati correnti dell'oggetto per determinare il relativo stato attuale. Prima che tu possa inviare la richiesta di aggiornamento dei metadati con le modifiche che preferisci, un processo o un utente indipendente sostituisce l'oggetto. La tua richiesta di modifica dei metadati per il nuovo oggetto è ancora valida, ma ora è associata a dati dell'oggetto diversi da quelli previsti.
Evitare la race condition
Per evitare che si verifichino queste situazioni, devi utilizzare il numero di generazione
restituito nella richiesta iniziale per i metadati dell'oggetto, quindi utilizzare questo
valore in un prerequisito di corrispondenza alla generazione nella seconda richiesta. In questo modo, verifichi
che i metadati corrispondano correttamente ai dati o che la seconda richiesta
non vada a buon fine con un codice di risposta 412 Precondition Failed
, il che ti consente 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 un precondizione di corrispondenza della metagenerazione nella seconda richiesta.
Aggiornamento della copia locale
Se hai una copia locale di un oggetto archiviato in Cloud Storage, spesso vuoi che rimanga aggiornata con la copia archiviata nel bucket. Tuttavia, se l'oggetto archiviato nel bucket non cambia, non è consigliabile perdere tempo e risorse scaricandolo di nuovo, soprattutto se l'oggetto è di grandi dimensioni.
Per evitare download non necessari di contenuti ancora aggiornati, puoi utilizzare il numero di generazione della tua copia locale come valore in un prerequisito di mancata corrispondenza della generazione, che includi nella richiesta di download:
Se i dati nel bucket continuano a corrispondere alla tua copia locale, i numeri di generazione corrispondono e il prerequisito non va a buon fine. Di conseguenza, la richiesta complessiva non va a buon fine con 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 il prerequisito va a buon fine. 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.
- Ottieni i metadati di un oggetto, ad esempio il numero di generazione.
- Scopri di più sulla coerenza in Cloud Storage.
- Scopri di più sulle operazioni idempotenti condizionali che devono utilizzare precondizioni.