Richiedi precondizioni

Questa pagina illustra le precondizioni delle richieste, utilizzate per impedire l'applicazione delle richieste a una risorsa quando quest'ultima si trova in uno stato imprevisto.

introduzione

Quando in una richiesta a Cloud Storage vengono utilizzate le precondizioni, la richiesta proviene solo se la risorsa scelta come target soddisfa i criteri definiti nelle precondizioni. I controlli delle condizioni preliminari assicurano che un bucket o un oggetto sia nello stato previsto, consentendoti di eseguire operazioni condizionali e aggiornamenti di lettura, modifica e scrittura sicuri.

Le precondizioni vengono spesso utilizzate per evitare che le condizioni di gara in richieste mutanti, 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, consulta Esempi di condizioni di gara e danneggiamento dei dati. Le precondizioni vengono spesso utilizzate anche per recuperare metadati e dati degli oggetti in richieste successive, per garantire che l'oggetto non sia cambiato nel tempo tra le due richieste.

Criteri di pre-condizione

Cloud Storage supporta l'utilizzo di diverse proprietà immutabili delle risorse nelle precondizioni:

Nella tabella seguente sono elencate le precondizioni 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 generation della risorsa di destinazione corrisponde al valore utilizzato nella precondizione. 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 metageneration della risorsa di destinazione corrisponde al valore utilizzato nella precondizione. Se i valori non corrispondono, la richiesta non riesce e restituisce una risposta 412 Precondition Failed.
ifGenerationNotMatch parametro di query N/D La richiesta procede se il valore generation della risorsa di destinazione non corrisponde al valore utilizzato nella precondizione. Se i valori corrispondono, la richiesta non riesce e restituisce una risposta 304 Not Modified.
ifMetagenerationNotMatch parametro di query N/D La richiesta procede se il valore metageneration della risorsa di destinazione non corrisponde al valore utilizzato nella precondizione. 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 ETag della risorsa di destinazione corrisponde al valore utilizzato nella precondizione. 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 precondizione. Se i valori corrispondono, la richiesta non riesce e restituisce una risposta 304 Not Modified.
N/D Intestazione If-Modified-Since La richiesta continua se la risorsa di destinazione ha una data Last-Modified successiva al valore utilizzato nella precondizione. Se la risorsa di destinazione non soddisfa questa condizione preliminare, la richiesta non riesce e restituisce 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 condizione preliminare. Se la risorsa di destinazione non soddisfa questa condizione preliminare, la richiesta non riesce e restituisce una risposta 412 Precondition Failed.

Precondizioni per la composizione degli oggetti

Durante l'esecuzione della composizione degli oggetti, sia l'API JSON che l'API XML supportano quanto segue:

  • Le precondizioni di corrispondenza della generazione e della corrispondenza di metagenerazione per l'oggetto di destinazione.

  • La precondizione della 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, l'operazione compose avrà esito negativo con una risposta 412 Precondition Failed.

Precondizioni per la copia degli oggetti

Quando copi o riscrivi un oggetto all'interno di Cloud Storage, sia l'API JSON che l'API XML supportano l'utilizzo di precondizioni standard per l'oggetto di destinazione. Ogni API dispone di supporto aggiuntivo per la 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 che hanno come prefisso ifSource.

  • Per l'oggetto di origine possono essere utilizzate tutte le precondizioni supportate dall'API XML. Queste precondizioni sono specificate nelle intestazioni con prefisso x-goog-copy-source-.

Il valore 0 in una condizione preliminare di corrispondenza della generazione

La precondizione della corrispondenza di generazione accetta il valore 0 come caso speciale. Quando una precondizione di corrispondenza della generazione con un valore di 0 viene inclusa in una richiesta, la richiesta procede solo se nel bucket non sono presenti oggetti con il nome specificato o se nel bucket sono presenti solo versioni non correnti dell'oggetto. Se è presente una versione live con il nome specificato, la richiesta non va a buon fine con il codice di stato 412 Precondition Failed.

Best practice e considerazioni

  • Puoi utilizzare più precondizioni in una singola richiesta. Se non viene soddisfatta una delle precondizioni, 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 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. Questo impedisce che la richiesta abbia successo su un altro oggetto che, per puro caso, ha un numero di metagenerazione che supera la precondizione.

  • Per i bucket che hanno versioni oggetto live e non attuali, le richieste di oggetti non si applicano alle versioni non correnti, a meno che un numero di generazione non venga incluso esplicitamente nella richiesta. Ciò significa che, per una richiesta generale che utilizza le precondizioni, la richiesta ha esito negativo se la versione live non corrisponde alla precondizione, indipendentemente dal fatto che una versione non corrente soddisfi o meno le precondizioni.

  • In genere dovresti usare 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 ai metadati, fornendo una garanzia più efficace rispetto agli ETag. Inoltre, i numeri di generazione e metagenerazione sono coerenti nelle API, mentre gli ETag no.

  • Le precondizioni non possono essere utilizzate nei caricamenti multiparte dell'API XML. Se provi a farlo, viene visualizzato un errore 400 NotImplemented.

Costo delle condizioni preliminari

Molte architetture che utilizzano le precondizioni richiedono di effettuare una richiesta di metadati degli oggetti prima della richiesta principale, al fine di determinare il numero di generazione e/o di metagenerazione attuale:

  • Con una richiesta aggiuntiva puoi raddoppiare la parte di rete della latenza complessiva delle operazioni aggiungendo un round trip extra, che potrebbe essere un fattore importante nelle operazioni sensibili alla latenza.

A seconda dell'applicazione, esistono modi per ridurre l'impatto dell'utilizzo di precondizioni, come ad esempio:

  • Memorizzazione dei numeri di generazione e metagenerazione degli oggetti a livello locale in modo da conoscere già i numeri corretti da utilizzare nella precondizione.
  • Avere la conoscenza dell'applicazione in merito agli 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 della corrispondenza della generazione in una richiesta per caricare un oggetto. Affinché la richiesta vada a buon fine, 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 specificato 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

  1. Assicurati che gcloud CLI sia installato e inizializzatoper 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.

  2. Utilizza cURL per chiamare l'API JSON con una richiesta Oggetto POST:

    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 da assegnare all'oggetto. Ad esempio, dog.png.
    • GENERATION è il numero di generazione previsto dell'oggetto che stai sostituendo. Ad esempio, 1122334455667788.

API XML

  1. Assicurati che gcloud CLI sia installato e inizializzatoper 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.

  2. Utilizza cURL per chiamare l'API XML con una richiesta PUT oggetto:

    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 da assegnare all'oggetto. Ad esempio, dog.png.

Scenari per l'utilizzo delle precondizioni

Gli scenari seguenti esplorano condizioni di gara ed esempi di memorizzazione nella cache che sfruttano l'uso delle precondizioni.

Nuovi tentativi di richieste multiple

Cloud Storage è un sistema distribuito. Poiché le richieste possono avere esito negativo a causa delle condizioni della rete o del servizio, il metodo consigliato per ritentare gli errori è 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. Successivamente, devi aggiungere al bucket un nuovo oggetto con lo stesso nome. A questo scopo, emetti una richiesta di eliminazione per eliminare l'oggetto. Tuttavia, una condizione di rete, come la perdita temporanea di 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, emetti una seconda richiesta di eliminazione per l'oggetto, che ha esito positivo, e ricevi una risposta che conferma l'eliminazione. Un minuto dopo, carichi un nuovo file.txt e il caricamento viene eseguito correttamente.

Si verifica una race condition se il router che ha perso la connettività successivamente la riprende e invia la richiesta di eliminazione originale, apparentemente persa, a Cloud Storage. Quando la richiesta arriva a Cloud Storage, viene eseguita correttamente perché è presente un nuovo file.txt. Cloud Storage invia una risposta che non ricevi perché il tuo client ha smesso di ascoltarla. Non solo il nuovo file viene eliminato, contrariamente alle tue intenzioni, ma anche non sai che è avvenuta la seconda eliminazione.

Il seguente diagramma illustra cosa è successo:

Evitare la race condition

Per evitare che si verifichi la situazione di cui sopra, devi iniziare a scaricare i metadati per file.txt per determinarne la generazione attuale. Successivamente, utilizza la generazione in una condizione preliminare di corrispondenza della generazione che includi come parte della richiesta di eliminazione. La precondizione assicura che venga eliminato solo l'oggetto con quel numero di generazione specifico, 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 condizione preliminare. Eventuali tentativi involontari di eliminare una generazione di file.txt diversa non riusciranno con il codice di risposta 412 Precondition Failed.

Poiché interruzioni di rete simili potrebbero causare condizioni di gara per la richiesta di caricamento che ha fatto seguito alla tua richiesta di eliminazione, puoi evitare molte di queste condizioni di gara utilizzando il valore 0 in una condizione di corrispondenza della generazione inclusa nella richiesta di caricamento. L'uso di questa precondizione assicura che i nuovi tentativi di caricamento non scrivano accidentalmente due volte l'oggetto, poiché la precondizione consente alla richiesta di procedere solo se non esistono generazioni attuali dell'oggetto.

Se applichi queste precondizioni, puoi proteggere i tuoi dati dalla perdita accidentale quando esegui le richieste di eliminazione e caricamento. Come illustrato dal 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, 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 relativa ai dati dell'oggetto è ancora andata a buon fine, ma ora disponi dei metadati dell'oggetto precedente e dei dati di quello nuovo.

  • Vuoi aggiornare i metadati di un oggetto, quindi recupera 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 da un utente indipendente. La tua richiesta di modifica dei metadati per il nuovo oggetto è ancora andata a buon fine, ma ora è associata a dati dell'oggetto diversi dal previsto.

Evitare la race condition

Per evitare che si verifichino queste situazioni, utilizza il numero di generazione restituito nella richiesta iniziale di metadati degli oggetti, quindi utilizza questo valore in una condizione preliminare di corrispondenza della generazione nella seconda richiesta. In questo modo i metadati corrispondono correttamente ai dati o 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 variare tra la prima e la seconda richiesta, puoi anche copiare il numero di metagenerazione trovato nella richiesta iniziale e utilizzarlo in una precondizione della corrispondenza di metagenerazione nella seconda richiesta.

Aggiornamento della copia locale

Se disponi di una copia locale di un oggetto archiviato in Cloud Storage, spesso è consigliabile che la copia locale sia sempre aggiornata con la copia archiviata nel bucket. Tuttavia, se l'oggetto archiviato nel bucket non cambia, non vuoi perdere tempo e risorse a 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 condizione preliminare di generazione senza corrispondenza, che includi nella richiesta di download:

  • Se i dati nel bucket continuano a corrispondere alla copia locale, i numeri di generazione corrispondono, causando l'errore della precondizione. Di conseguenza, la richiesta complessiva ha esito negativo con una risposta 304 Not Modified e i dati non vengono scaricati inutilmente.

  • Se i dati nel tuo bucket sono cambiati, i numeri di generazione non corrispondono e la precondizione viene soddisfatta. Ciò significa che la richiesta complessiva viene eseguita normalmente e viene scaricata la versione aggiornata dei contenuti.

Passaggi successivi