Questa pagina descrive le precondizioni delle richieste, che utilizzi per impedire che le richieste vengano applicate a una risorsa quando questa si trova in uno stato imprevisto.
Introduzione
Quando le precondizioni vengono utilizzate in una richiesta a Cloud Storage, la richiesta procede solo se la risorsa di destinazione soddisfa i criteri definiti nelle precondizioni. I controlli delle precondizioni assicurano che un bucket o un oggetto si trovi nello stato previsto, consentendoti di eseguire aggiornamenti di lettura-modifica-scrittura sicuri e operazioni condizionali.
Le precondizioni vengono spesso utilizzate per evitare condizioni di competizione nelle richieste di mutazione, come caricamenti, eliminazioni o aggiornamenti dei metadati. Le condizioni di competizione possono verificarsi quando la stessa richiesta viene inviata ripetutamente o quando processi indipendenti tentano di modificare la stessa risorsa. Per saperne di più, consulta Esempi di race condition e danneggiamento dei dati. Le precondizioni vengono spesso utilizzate anche per recuperare i metadati e i dati degli oggetti in richieste successive, per garantire che l'oggetto non sia cambiato nel tempo tra le due richieste.
Criteri di precondizione
Cloud Storage supporta l'utilizzo di diverse proprietà di risorse immutabili nelle precondizioni:
- Numeri di generazione e metagenerazione
- ETags
- La data
Last-Modified
(disponibile solo quando si recuperano dati o metadati degli oggetti utilizzando l'API XML)
La tabella seguente elenca le precondizioni supportate 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 il valore generation della risorsa di destinazione corrisponde al valore utilizzato nella precondizione. 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 il valore metageneration della risorsa di destinazione corrisponde al valore utilizzato nella precondizione. 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 il generation della risorsa di destinazione non corrisponde al valore utilizzato nella precondizione. Se i valori corrispondono, la richiesta non va a buon fine e viene restituita una risposta 304 Not Modified . |
Parametro di query ifMetagenerationNotMatch |
N/D | La richiesta procede se il metageneration della risorsa di destinazione non corrisponde al valore utilizzato nella precondizione. Se i valori corrispondono, la richiesta non va a buon fine e viene restituita una risposta 304 Not Modified . |
Intestazione If-Match |
Intestazione If-Match |
Applicabile alle richieste che recuperano dati. La richiesta procede se il valore ETag della risorsa di destinazione corrisponde al valore utilizzato nella precondizione. 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 dati. La richiesta procede se il ETag della risorsa di destinazione non corrisponde al valore utilizzato nella precondizione. Se i valori corrispondono, la richiesta non va a buon fine e viene restituita 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 nella precondizione. Se la risorsa di destinazione non soddisfa questa precondizione, 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 nella precondizione. Se la risorsa di destinazione non soddisfa questa precondizione, la richiesta non va a buon fine e viene restituita una risposta 412 Precondition Failed . |
Precondizioni per la composizione dell'oggetto
Quando esegui la composizione di oggetti, sia l'API JSON sia l'API XML supportano quanto segue:
Le precondizioni generation-match e metageneration-match per l'oggetto di destinazione.
La precondizione di corrispondenza della generazione per ogni oggetto di origine. L'utilizzo di questa precondizione 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 un'operazione di sovrascrittura, le operazioni
compose
non vanno a buon fine e viene restituita 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 precondizioni standard per l'oggetto di destinazione. Ogni API supporta ulteriori precondizioni per gli oggetti origine:
L'API JSON supporta le precondizioni di generazione e metagenerazione per l'oggetto di origine, che vengono specificate utilizzando parametri di ricerca con il prefisso
ifSource
.Per l'oggetto di origine possono essere utilizzate tutte le precondizioni supportate dall'API XML. Queste precondizioni sono specificate nelle intestazioni con il prefisso
x-goog-copy-source-
.
Il valore di 0
in una precondizione di corrispondenza della generazione
La precondizione di corrispondenza della generazione accetta il valore 0
come caso speciale. Quando
in una richiesta è inclusa una precondizione di corrispondenza della 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 live con il nome specificato, la richiesta non va a buon fine e viene restituito un
codice di stato 412 Precondition Failed
.
Best practice e considerazioni
Puoi utilizzare più precondizioni in un'unica richiesta. Se una delle precondizioni non viene soddisfatta, la richiesta complessiva non va a buon fine.
I bucket non hanno un numero di generazione, ma un numero di metagenerazione. Non devi utilizzare precondizioni che specificano un numero di generazione in una richiesta di bucket.
Se utilizzi una precondizione di metagenerazione in una richiesta di oggetto, devi sempre utilizzare anche una precondizione di generazione. In questo modo, la richiesta non andrà a buon fine su un oggetto diverso che ha casualmente un numero di metagenerazione che supera la precondizione.
Per i bucket che hanno versioni degli oggetti attive e 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 precondizioni, la richiesta non va a buon fine se la versione live non corrisponde alla precondizione, indipendentemente dal fatto che una versione non corrente corrisponda o meno alle precondizioni.
In genere, dovresti utilizzare le precondizioni di generazione e metagenerazione anziché quelle ETag. I numeri di generazione e metagenerazione tengono traccia di tutti gli aggiornamenti degli oggetti, comprese le modifiche ai metadati, fornendo 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.
Le precondizioni non possono essere utilizzate nei caricamenti multiparte dell'API XML. Il tentativo di farlo genera 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, 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 round trip aggiuntivo, che potrebbe essere un fattore importante nelle operazioni sensibili alla latenza.
- Una richiesta aggiuntiva comporta un costo per operazione e, nella maggior parte dei casi, un costo di rete.
A seconda dell'applicazione, esistono modi per ridurre gli impatti dell'utilizzo delle precondizioni, ad esempio:
- Memorizzazione locale dei numeri di generazione e metagenerazione degli oggetti in modo da conoscere già i numeri corretti da utilizzare nella precondizione.
- Avere la conoscenza dell'applicazione di quali oggetti sono stati creati di recente, in modo da sapere già quando utilizzare la precondizione
if-generation-match:0
.
Esempio: utilizzo di una precondizione
L'esempio seguente utilizza la precondizione di corrispondenza della generazione in una richiesta per caricare un oggetto. Affinché la richiesta possa procedere, deve esistere un oggetto preesistente memorizzato nel bucket con il nome specificato e il numero di generazione dell'oggetto preesistente deve corrispondere al numero fornito nella precondizione:
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
Avere gcloud CLI installata e inizializzata, il che ti 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 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 dare al tuo oggetto. Ad esempio,dog.png
.GENERATION
è il numero di generazione previsto dell'oggetto che stai sostituendo. Ad esempio,1122334455667788
.
API XML
Avere gcloud CLI installata e inizializzata, il che ti consente di generare un token di accesso per l'intestazione
Authorization
.Utilizza
cURL
per chiamare l'API XML con una richiestaPUT
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 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 dare al tuo oggetto. Ad esempio,dog.png
.
Scenari per l'utilizzo delle precondizioni
Gli scenari seguenti esplorano esempi di condizioni di competizione e memorizzazione nella cache che traggono vantaggio dall'utilizzo di precondizioni.
Più tentativi di richiesta
Cloud Storage è un sistema distribuito. Poiché le richieste possono non andare a buon fine a causa di condizioni di rete o di servizio, il modo consigliato per riprovare è con il backoff esponenziale. Tuttavia, a causa della natura dei sistemi distribuiti, a volte questi tentativi possono causare un comportamento sorprendente.
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, invia una richiesta di eliminazione dell'oggetto. Tuttavia, una condizione di rete, ad esempio un router intermedio
che perde temporaneamente la connettività, impedisce alla richiesta di raggiungere
Cloud Storage e non ricevi una risposta.
Poiché non hai ricevuto una risposta alla prima richiesta, invii una seconda
richiesta di 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 riacquisisce e invia la richiesta di eliminazione originale, apparentemente persa, a Cloud Storage. Quando la richiesta arriva a Cloud Storage, ha esito positivo 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 ti accorgi che si è verificata la seconda eliminazione.
Il seguente diagramma mostra cosa è successo:
Prevenzione della race condition
Per evitare che si verifichi la situazione sopra descritta, devi innanzitutto recuperare i
metadati per file.txt
per determinare la generazione attuale. Poi
utilizzi la generazione in una precondizione di corrispondenza della generazione che includi come parte
della richiesta di eliminazione. La precondizione garantisce che venga eliminato solo l'oggetto con quel numero di generazione specifico, indipendentemente da quando la richiesta di eliminazione raggiunge Cloud Storage o da quante volte viene inviata la richiesta di eliminazione con la precondizione. Qualsiasi tentativo involontario di eliminare una generazione diversa
di file.txt
non va a buon fine e restituisce il codice di risposta 412 Precondition Failed
.
Poiché interruzioni di rete simili potrebbero causare race condition per la richiesta di caricamento
che ha seguito la tua richiesta di eliminazione, puoi evitare molte di queste race
condition utilizzando il valore 0
in una precondizione di corrispondenza della generazione
inclusa nella richiesta di caricamento. L'utilizzo di questa precondizione garantisce che i tentativi di
caricamento non scrivano accidentalmente l'oggetto due volte, perché la precondizione
consente di procedere con la richiesta solo se non esistono generazioni correnti
dell'oggetto.
Con queste precondizioni, proteggi i tuoi dati da eventuali perdite accidentali quando esegui le richieste di eliminazione e caricamento. Questo può essere visto nel seguente diagramma:
Associazione dei metadati degli oggetti
I dati e i metadati di un oggetto sono entità separate 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 separate. Richiedi prima 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 per i dati dell'oggetto ha comunque 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 attuali dell'oggetto per determinarne lo stato attuale. Prima di poter inviare la richiesta di aggiornamento dei metadati con le modifiche desiderate, un processo o utente indipendente sostituisce l'oggetto. La richiesta di modifica dei metadati per il nuovo oggetto è ancora valida, ma ora è associata a dati dell'oggetto diversi da quelli che avevi previsto.
Prevenzione della race condition
Per evitare che si verifichino queste situazioni, devi utilizzare il numero di generazione restituito nella richiesta iniziale dei metadati dell'oggetto e poi utilizzare questo valore in una precondizione di corrispondenza della generazione nella seconda richiesta. In questo modo, i metadati corrispondono correttamente ai dati oppure la seconda richiesta non va a buon fine con un codice di risposta 412 Precondition Failed
, consentendoti 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
Nei casi in cui hai una copia locale di un oggetto archiviato 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 vuoi sprecare tempo e risorse per scaricarlo di nuovo, soprattutto se l'oggetto è di grandi dimensioni.
Per evitare download inutili di contenuti ancora recenti, puoi utilizzare il numero di generazione della tua copia locale come valore in una precondizione di mancata corrispondenza della generazione, che includi nella richiesta di download:
Se i dati nel bucket continuano a corrispondere alla copia locale, i numeri di generazione corrispondono, causando l'esito negativo della precondizione. Di conseguenza, la richiesta complessiva non va a buon fine e viene restituita 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 precondizione 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.
- Recupera 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 le precondizioni.