Questa pagina illustra le precondizioni delle richieste, che utilizzi per impedire che le richieste vengano applicate a una risorsa quando la risorsa 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 race in richieste di mutazione, come caricamenti, eliminazioni o aggiornamenti dei metadati. Le condizioni di race possono verificarsi quando la stessa richiesta viene inviata ripetutamente o quando processi indipendenti tentano di modificare la stessa risorsa. Per ulteriori informazioni, consulta Esempi di condizioni di race e danneggiamento dei dati. Le precondizioni vengono spesso utilizzate anche quando si recuperano 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à delle risorse immutabili nelle precondizioni:
- Numeri di generazione e metagenerazione
- ETags
- La data
Last-Modified(disponibile solo quando si recuperano i dati o i 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 |
x-goog-if-generation-match intestazione |
La richiesta procede se la 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 |
x-goog-if-metageneration-match intestazione |
La richiesta procede se la 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 la 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 la 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 i dati. La richiesta procede se l'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. |
If-None-Match intestazione |
If-None-Match intestazione |
Applicabile alle richieste che recuperano i dati. La richiesta procede se l'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 | If-Modified-Since intestazione |
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 | If-Unmodified-Since intestazione |
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 di composizione degli oggetti
Quando si esegue la composizione degli oggetti, sia l'API JSON sia l' API XML supportano quanto segue:
Le precondizioni di corrispondenza della generazione e della metagenerazione 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 una sovrascrittura di questo tipo, le operazioni
composenon vanno a buon fine e viene restituita una risposta412 Precondition Failed.
Precondizioni di 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 ha un supporto aggiuntivo per le precondizioni 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 con il prefisso
ifSource.Tutte le precondizioni supportate dall'API XML possono essere utilizzate per l'oggetto di origine. Queste precondizioni vengono specificate nelle intestazioni con il prefisso
x-goog-copy-source-.
Il valore 0 in una precondizione di corrispondenza della generazione
La precondizione di corrispondenza della generazione accetta il valore 0 come caso speciale. Quando una precondizione di corrispondenza della generazione con un valore di 0 è inclusa in una richiesta, 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 il codice di stato 412 Precondition Failed.
Best practice e considerazioni
Puoi utilizzare più precondizioni in una singola 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 hanno 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 oggetti, devi sempre utilizzare anche una precondizione di generazione. In questo modo, la richiesta non va a buon fine su un oggetto diverso che, per coincidenza, ha un numero di metagenerazione che supera la precondizione.
Per i bucket che hanno versioni degli oggetti live e non correnti, le richieste di oggetti non si applicano alle versioni non correnti, a meno che non sia incluso esplicitamente un numero di generazione 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 corrisponde alla precondizione, indipendentemente dal fatto che una versione non corrente corrisponda o meno alle precondizioni.
In genere, devi 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, incluse le modifiche dei 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 le precondizioni richiedono di effettuare una richiesta di metadati degli oggetti 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'andata e ritorno aggiuntiva, che potrebbe essere un fattore importante nelle operazioni sensibili alla latenza.
- Una richiesta aggiuntiva comporta un costo dell'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:
- Archiviazione locale dei numeri di generazione e metagenerazione degli oggetti, in modo da conoscere già i numeri corretti da utilizzare nella precondizione.
- Conoscenza dell'applicazione degli oggetti appena creati, 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 di caricamento di un oggetto. Affinché la richiesta proceda, nel bucket deve essere archiviato un oggetto preesistente 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
Assicurati che gcloud CLI sia installato e inizializzato, in modo da poter generare un token di accesso per l'intestazione
Authorization.Utilizza
cURLper chiamare l'API JSON con unaPOSTrichiesta di oggetti: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 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
Assicurati che gcloud CLI sia installato e inizializzato, in modo da poter generare un token di accesso per l'intestazione
Authorization.Utilizza
cURLper chiamare l'API XML con unaPUTrichiesta di oggetti: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 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
I seguenti scenari esplorano le condizioni di race e gli esempi di memorizzazione nella cache che traggono vantaggio dall'utilizzo delle 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 in caso di errori è con 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. Dopodiché, vuoi aggiungere un nuovo oggetto con lo stesso nome al bucket. Per farlo, invii 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 riacquista e invia la richiesta di eliminazione originale, apparentemente persa, a Cloud Storage. Quando la richiesta arriva a Cloud Storage, va a buon fine 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 nemmeno a conoscenza della 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 di file.txt per determinarne la generazione corrente. Quindi, utilizzi la generazione in una precondizione di corrispondenza della generazione che includi nella 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 non intenzionale di eliminare una generazione diversa di file.txt non va a buon fine e viene restituito il codice di risposta 412 Precondition Failed.
Poiché interruzioni di rete simili potrebbero causare condizioni di race per la richiesta di caricamento
che ha seguito la richiesta di eliminazione, puoi evitare molte di queste condizioni di race
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 alla richiesta di procedere solo se non sono presenti generazioni correnti dell'oggetto.
Con queste precondizioni, proteggi i tuoi dati dalla perdita accidentale durante l'esecuzione delle richieste di eliminazione e caricamento. Questo è visibile 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 richiesta dei dati dell'oggetto va comunque a buon fine, ma ora hai i metadati del vecchio oggetto e i dati del nuovo oggetto.
Vuoi aggiornare i metadati di un oggetto, quindi recuperi i metadati correnti dell'oggetto per determinarne lo stato attuale. Prima di poter inviare la richiesta di aggiornamento dei metadati con le modifiche desiderate, un processo o un utente indipendente sostituisce l'oggetto. La richiesta di modifica dei metadati del nuovo oggetto va comunque a buon fine, 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 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 e viene restituito il codice di risposta 412 Precondition Failed, 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 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 rimanga 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 aggiornati, puoi utilizzare il numero di generazione della copia locale come valore in una precondizione di non 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 il fallimento della precondizione. Di conseguenza, la richiesta complessiva non va a buon fine e viene restituita una risposta
304 Not Modifiede i dati non vengono scaricati inutilmente.Se i dati nel bucket sono cambiati, i numeri di generazione non corrispondono e la precondizione 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.
- 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 condizionalmente idempotenti che devono utilizzare le precondizioni.