Introduzione all'API BigQuery Storage Write

L'API BigQuery Storage Write è un'API unificata di importazione dati per BigQuery. che combina l'importazione di flussi di dati e il caricamento in batch in un'unica API ad alte prestazioni. Puoi utilizzare l'API Storage Write per caricare i record in BigQuery in tempo reale o per elaborare in batch un numero arbitrariamente elevato di record e sottoporli a commit in un'unica operazione atomica.

Vantaggi dell'utilizzo dell'API Storage Write

Semantica di consegna "exactly-once". L'API Storage Write supporta la semantica "exactly-once" tramite l'utilizzo degli offset dello stream. A differenza del metodo tabledata.insertAll, l'API Storage Write non scrive mai due messaggi con lo stesso offset all'interno di uno stream, se il client fornisce gli offset dello stream quando aggiunge i record.

Transazioni a livello di stream. Puoi scrivere dati in uno stream e applicare il commit come singola transazione. Se l'operazione di commit non va a buon fine, puoi ritentare in tutta sicurezza.

Transazioni tra stream. Più worker possono creare i propri stream per elaborare i dati in modo indipendente. Quando tutti i worker hanno terminato, puoi committare tutti gli stream come transazione.

Protocollo efficiente. L'API Storage Write è più efficiente rispetto al metodo insertAll precedente perché utilizza lo streaming gRPC anziché REST su HTTP. L'API Storage Write supporta anche i formati binari sotto forma di buffer di protocollo, che sono un formato di trasmissione più efficiente del JSON. Le richieste di scrittura sono asincrone con ordinamento garantito.

Rilevamento degli aggiornamenti dello schema. Se lo schema della tabella sottostante cambia durante lo streaming del client, l'API Storage Write invia una notifica al client. Il client può decidere se riconnettersi utilizzando lo schema aggiornato o continuare a scrivere nella connessione esistente.

Costo inferiore. L'API Storage Write ha un costo notevolmente inferiore rispetto all'API di inserimento di flussi insertAll precedente. Inoltre, puoi importare fino a 2 TiB al mese gratuitamente.

Autorizzazioni obbligatorie

Per utilizzare l'API Storage Write, devi disporre delle autorizzazionibigquery.tables.updateData.

I seguenti ruoli IAM (Identity and Access Management) predefiniti includono le autorizzazioni bigquery.tables.updateData:

  • bigquery.dataEditor
  • bigquery.dataOwner
  • bigquery.admin

Per ulteriori informazioni sui ruoli e sulle autorizzazioni IAM in BigQuery, consulta Ruoli e autorizzazioni predefiniti.

Ambiti di autenticazione

L'utilizzo dell'API Storage Write richiede uno dei seguenti ambiti OAuth:

  • https://www.googleapis.com/auth/bigquery
  • https://www.googleapis.com/auth/cloud-platform
  • https://www.googleapis.com/auth/bigquery.insertdata

Per ulteriori informazioni, consulta la Panoramica dell'autenticazione.

Panoramica dell'API Storage Write

L'astrazione di base nell'API Storage Write è uno stream. Uno stream scrive i dati in una tabella BigQuery. Più stream possono scrivere contemporaneamente nella stessa tabella.

Stream predefinito

L'API Storage Write fornisce uno stream predefinito, progettato per scenari di streaming in cui i dati arrivano continuamente. Ha le seguenti caratteristiche:

  • I dati scritti nello stream predefinito sono immediatamente disponibili per le query.
  • Lo stream predefinito supporta la semantica almeno una volta.
  • Non è necessario creare esplicitamente lo stream predefinito.

Se esegui la migrazione dall'API tabledata.insertall precedente, ti consigliamo di utilizzare lo stream predefinito. Ha una semantica di scrittura simile, con una maggiore resilienza dei dati e meno limitazioni di scalabilità.

Flusso dell'API:

  1. AppendRows (loop)

Per ulteriori informazioni e codice di esempio, consulta Utilizzare lo stream predefinito per la semantica almeno una volta.

Stream creati dall'applicazione

Puoi creare uno stream esplicitamente se hai bisogno di uno dei seguenti comportamenti:

  • Semantika di scrittura esattamente una volta tramite l'utilizzo di offset dello stream.
  • Supporto di proprietà ACID aggiuntive.

In generale, gli stream creati dall'applicazione offrono un maggiore controllo sulla funzionalità, ma con un costo aggiuntivo in termini di complessità.

Quando crei uno stream, devi specificare un tipo. Il tipo controlla quando i datiscritti nello stream diventano visibili in BigQuery per la lettura.

Tipo in attesa

Nel tipo in attesa, i record vengono memorizzati nella memoria intermedia in uno stato in attesa finché non esegui il commit dello stream. Quando esegui il commit di uno stream, tutti i dati in attesa diventano disponibili per la lettura. Il commit è un'operazione atomica. Utilizza questo tipo per i carichi di lavoro batch, come alternativa ai job di caricamento BigQuery. Per ulteriori informazioni, consulta Caricare i dati in batch utilizzando l'API Storage Write.

Flusso dell'API:

  1. CreateWriteStream
  2. AppendRows (loop)
  3. FinalizeWriteStream
  4. BatchCommitWriteStreams

Tipo di impegno

Nel tipo di commit, i record sono disponibili per la lettura non appena li scrivi nello stream. Utilizza questo tipo per i carichi di lavoro in streaming che richiedono una latenza di lettura minima. Lo stream predefinito utilizza una forma almeno una volta del tipo di commit. Per ulteriori informazioni, consulta Utilizzare il tipo di commit per la semantica esattamente una volta.

Flusso dell'API:

  1. CreateWriteStream
  2. AppendRows (loop)
  3. FinalizeWriteStream (facoltativo)

Tipo di buffering

Il tipo con buffer è un tipo avanzato che in genere non deve essere utilizzato, tranne con il connettore Apache Beam BigQuery I/O. Se hai piccoli batch che vuoi garantire che vengano visualizzati insieme, utilizza il tipo impegnato e invia ogni batch in una richiesta. In questo tipo, vengono forniti commit a livello di riga e i record vengono memorizzati in un buffer fino al commit delle righe tramite svuotamento dello stream.

Flusso dell'API:

  1. CreateWriteStream
  2. AppendRowsFlushRows (loop)
  3. FinalizeWriteStream (facoltativo)

Selezione di un tipo

Utilizza il seguente diagramma di flusso per decidere quale tipo è più adatto al tuo carico di lavoro:

immagine

Dettagli API

Tieni presente quanto segue quando utilizzi l'API Storage Write:

AppendRows

Il metodo AppendRows aggiunge uno o più record allo stream. La prima chiamata a AppendRows deve contenere un nome stream insieme allo schema dei dati, specificato come DescriptorProto. Come best practice, invia un batch di righe in ogni chiamata AppendRows. Non inviare una riga alla volta.

Gestione del buffer di proto

I buffer di protocollo forniscono un meccanismo estensibile, indipendente dal linguaggio e dalla piattaforma per la serializzazione dei dati strutturati in modo compatibile con le versioni precedenti e future. Sono vantaggiosi in quanto forniscono uno spazio di archiviazione dei dati compatto con analisi rapida ed efficiente. Per scoprire di più sui buffer di protocollo, consulta la Panoramica dei buffer di protocollo.

Se intendi utilizzare l'API direttamente con un messaggio predefinito del buffer di protocollo, il messaggio del buffer di protocollo non può utilizzare un specificatore package e tutti i tipi nidificati o di enumerazione devono essere definiti all'interno del messaggio principale di primo livello. Non sono consentiti riferimenti a messaggi esterni. Per un esempio, consulta sample_data.proto.

I client Java e Go supportano buffer di protocollo arbitrari, perché la libreria client normalizza lo schema del buffer di protocollo.

FinalizeWriteStream

Il metodo FinalizeWriteStream finalizza lo stream in modo che non sia possibile aggiungere nuovi dati. Questo metodo è obbligatorio nel tipo Pending e facoltativo nei tipi Committed e Buffered. Lo stream predefinito non supporta questo metodo.

Gestione degli errori

Se si verifica un errore, l'oggetto google.rpc.Status restituito può includere un valore StorageError nei dettagli dell'errore. Esamina StorageErrorCode per trovare il tipo di errore specifico. Per maggiori informazioni sul modello di errore dell'API Google, consulta Errori.

Connessioni

L'API Storage Write è un'API gRPC che utilizza connessioni bidirezionali. Il metodo AppendRows crea una connessione a uno stream. Puoi aprire più connessioni nello stream predefinito. Questi aggiunte sono asincrone, il che ti consente di inviare contemporaneamente una serie di scritture. I messaggi di risposta su ogni connessione bidirezionale arrivano nello stesso ordine in cui sono state inviate le richieste.

Gli stream creati dall'applicazione possono avere una sola connessione attiva. Come best practice, limita il numero di connessioni attive, e utilizza una connessione per il maggior numero possibile di scritture di dati. Quando utilizzi lo stream predefinito in Java o Go, puoi utilizzare il multiplexing dell'API Storage Write per scrivere in più tabelle di destinazione con connessioni condivise.

In genere, una singola connessione supporta almeno 1 MBps di throughput. Il valore superiore dipende da diversi fattori, come la larghezza di banda della rete, lo schema dei dati e il carico del server. Quando una connessione raggiunge il limite di throughput, le richieste in entrata potrebbero essere rifiutate o messe in coda finché il numero di richieste in corso non diminuisce. Se hai bisogno di una maggiore velocità in uscita, crea più connessioni.

BigQuery chiude la connessione gRPC se rimane inattiva per troppo tempo. In questo caso, il codice di risposta è HTTP 409. La connessione gRPC può essere chiusa anche in caso di riavvio del server o per altri motivi. Se si verifica un errore di connessione, crea una nuova connessione. Le librerie client Java e Go si ricollegano automaticamente se la connessione viene chiusa.

Supporto della libreria client

Esistono librerie client per l'API Storage Write in più linguaggi di programmazione ed espongono i costrutti dell'API basata su gRPC sottostante. Questa API sfrutta funzionalità avanzate come lo streaming bidirezionale, che potrebbe richiedere un ulteriore lavoro di sviluppo per il supporto. A tal fine, per questa API sono disponibili una serie di astrazioni di livello superiore che semplificano queste interazioni e riducono i problemi degli sviluppatori. Ti consigliamo di utilizzare queste altre astrattizioni della libreria, se possibile.

Questa sezione fornisce ulteriori dettagli sui linguaggi e sulle librerie in cui sono state fornite agli sviluppatori funzionalità aggiuntive rispetto all'API generata.

Per visualizzare esempi di codice relativi all'API Storage Write, visita questa pagina.

Client Java

La libreria client Java fornisce due oggetti writer:

  • StreamWriter: accetta i dati in formato buffer di protocollo.

  • JsonStreamWriter: accetta i dati in formato JSON e li converte in buffer del protocollo prima di inviarli tramite rete. JsonStreamWriter supporta anche gli aggiornamenti automatici dello schema. Se lo schema della tabella cambia, lo scrittore si ricollega automaticamente al nuovo schema, consentendo al client di inviare i dati utilizzando il nuovo schema.

Il modello di programmazione è simile per entrambi gli autori. La differenza principale è il modo in cui formatti il payload.

L'oggetto writer gestisce una connessione all'API Storage Write. L'oggetto writer pulizia automatica delle richieste, aggiunge le intestazioni di instradamento regionale alle richieste e si ricollega dopo errori di connessione. Se utilizzi direttamente l'API gRPC, devi gestire questi dettagli.

Client Go

Il client Go utilizza un'architettura client-server per codificare i messaggi nel formato Protocol Buffer utilizzando proto2. Consulta la documentazione di Go per informazioni dettagliate su come utilizzare il client Go, con codice di esempio.

Client Python

Il client Python è un client di livello inferiore che racchiude l'API gRPC. Per utilizzare questo client, devi inviare i dati come buffer di protocollo, seguendo il flusso dell'API per il tipo specificato.

Evita di utilizzare la generazione di messaggi proto dinamici in Python perché le prestazioni della libreria non sono adeguate.

Per scoprire di più sull'utilizzo dei buffer di protocollo con Python, leggi il tutorial sulle nozioni di base dei buffer di protocollo in Python.

Client Node.js

La libreria client NodeJS accetta input JSON e fornisce il supporto per il ricoinvolgimento automatico. Per informazioni dettagliate su come utilizzare il client, consulta la documentazione.

Conversioni dei tipi di dati

La tabella seguente mostra i tipi di buffer del protocollo supportati per ogni tipo di dati BigQuery:

Tipo di dati BigQuery Tipi di buffer di protocollo supportati
BOOL bool, int32, int64, uint32, uint64, google.protobuf.BoolValue
BYTES bytes, string, google.protobuf.BytesValue
DATE int32 (opzione preferita), int64, string

Il valore è il numero di giorni dall'epoca Unix (1970-01-01). L' intervallo valido è compreso tra "-719162" (0001-01-01) e "2932896" (9999-12-31).

DATETIME, TIME string

Il valore deve essere un valore letterale DATETIME o TIME.

int64

Utilizza la classe CivilTimeEncoder per eseguire la conversione.

FLOAT double, float, google.protobuf.DoubleValue, google.protobuf.FloatValue
GEOGRAPHY string

Il valore è una geometria in formato WKT o GeoJson.

INTEGER int32, int64, uint32, enum, google.protobuf.Int32Value, google.protobuf.Int64Value, google.protobuf.UInt32Value
JSON string
NUMERIC, BIGNUMERIC int32, int64, uint32, uint64, double, float, string
bytes, google.protobuf.BytesValue

Utilizza la classe BigDecimalByteStringEncoder per eseguire la conversione.

STRING string, enum, google.protobuf.StringValue
TIME string

Il valore deve essere un letterale TIME.

TIMESTAMP int64 (opzione preferita), int32, uint32, google.protobuf.Timestamp

Il valore è espresso in microsecondi dall'epoca Unix (01/01/1970).

INTERVAL string, google.protobuf.Duration

Il valore della stringa deve essere un letterale INTERVAL.

RANGE<T> message

Un tipo di messaggio nidificato nel proto con due campi, start e end, dove entrambi i campi devono essere dello stesso tipo di buffer del protocollo supportato che corrisponde a un tipo di dati BigQuery T. T deve essere DATE, DATETIME o TIMESTAMP. Se un campo (start o end) non è impostato nel messaggio proto, rappresenta un confine illimitato. Nell'esempio seguente, f_range_date rappresenta una colonna RANGE in una tabella. Poiché il campo end non è impostato nel messaggio proto, il confine di fine di questo intervallo non è limitato.


{
  f_range_date: {
    start: 1
  }
}
REPEATED FIELD array

Un tipo di array nel proto corrisponde a un campo ripetuto in BigQuery.

RECORD message

Un tipo di messaggio nidificato nel proto corrisponde a un campo del record in BigQuery.

Gestire la mancata disponibilità

La ripetizione dei tentativi con backoff esponenziale può attenuare gli errori casuali e brevi periodi di mancata disponibilità del servizio, ma per evitare di eliminare righe durante periodi di mancata disponibilità prolungati è necessario un approccio più ponderato. In particolare, se un client non riesce a inserire una riga in modo persistente, che cosa deve fare?

La risposta dipende dai tuoi requisiti. Ad esempio, se BigQuery viene utilizzato per l'analisi operativa in cui alcune righe mancanti sono accettabili, il client può rinunciare dopo alcuni tentativi e ignorare i dati. Se invece ogni riga è fondamentale per l'attività, ad esempio per i dati finanziari, devi avere una strategia per mantenere i dati fino a quando non possono essere inseriti in un secondo momento.

Un modo comune per gestire gli errori persistenti è pubblicare le righe in un argomento Pub/Sub per la valutazione e l'eventuale inserimento futuri. Un altro metodo comune è la persistenza temporanea dei dati sul client. Entrambi i metodi possono mantenere i client sbloccati e, al contempo, garantire che tutte le righe possano essere inserite una volta ripristinata la disponibilità.

Partizionamento delle colonne per unità di tempo

Puoi eseguire lo streaming dei dati in una tabella partizionata in base a una colonna DATE, DATETIME o TIMESTAMP compresa tra 5 anni nel passato e 1 anno nel futuro. I dati al di fuori di questo intervallo vengono rifiutati.

Quando i dati vengono trasmessi in streaming, vengono inizialmente inseriti nella partizione __UNPARTITIONED__. Dopo aver raccolto dati non partizionati sufficienti, BigQuery li ripartisce nella partizione appropriata. Tuttavia, non esiste un accordo sul livello del servizio (SLA) che definisce il tempo necessario per il trasferimento dei dati dalla partizione __UNPARTITIONED__.

L'API Storage Write non supporta l'uso di decoratori della partizione.

Plug-in di output dell'API Storage Write di Fluent Bit

Il plug-in di output dell'API Storage Write di Fluent Bit automatizza il processo di importazione dei record JSON in BigQuery, eliminando la necessità di scrivere codice. Con questo plug-in, devi solo configurare un plug-in di input compatibile e impostare un file di configurazione per iniziare a eseguire lo streaming dei dati. Fluent Bit è un elaboratore e inoltro di log open source e cross-platform che utilizza plug-in di input e output per gestire diversi tipi di origini dati e sink.

Questo plug-in supporta quanto segue:

  • Semantika almeno una volta utilizzando il tipo predefinito.
  • Semantika esattamente una volta utilizzando il tipo di commit.
  • Scalabilità dinamica per gli stream predefiniti, quando è indicata la contropressione.

Metriche del progetto dell'API Storage Write

Per le metriche per monitorare l'importazione dati con l'API Storage Write, ad esempio la latenza a livello di richiesta lato server, le connessioni simultanee, i byte caricati e le righe caricate, consulta le metriche di Google Cloud.

Utilizzare data manipulation language (DML) con i dati sottoposti a streaming di recente

Puoi utilizzare data manipulation language (DML), ad esempio gli statement UPDATE, DELETE o MERGE, per modificare le righe scritte di recente in una tabella BigQuery dall'API BigQuery Storage Write. Le scritture recenti sono quelle che si sono verificate gli ultimi 30 minuti.

Per ulteriori informazioni sull'utilizzo di DML per modificare i dati in streaming, consulta Utilizzare il linguaggio di manipolazione dei dati.

Limitazioni

  • Il supporto per l'esecuzione di istruzioni DML con modifica sui dati sottoposti a streaming di recente non si estende ai dati sottoposti a streaming utilizzando l'API BigQuery Storage Write di tipo buffered
  • Il supporto per l'esecuzione di istruzioni DML con mutazioni sui dati sottoposti a streaming di recente non si estende ai dati sottoposti a streaming utilizzando l'API insertAll streaming.
  • L'esecuzione di istruzioni DML con mutazioni all'interno di una transazione con più istruzioni in base ai dati sottoposti a streaming di recente non è supportata.

Quote dell'API Storage Write

Per informazioni su quote e limiti dell'API Storage Write, consulta Quote e limiti dell'API BigQuery Storage Write.

Puoi monitorare l'utilizzo delle quote relative a connessioni simultanee e throughput nella pagina Quote della console Google Cloud.

Calcolare la velocità effettiva

Supponiamo che il tuo obiettivo sia raccogliere i log da 100 milioni di endpoint creando 1500 record di log al minuto. Poi puoi stimare il throughput come 100 million * 1,500 / 60 seconds = 2.5 GB per second. Devi assicurarti in anticipo di disporre di una quota adeguata per gestire questo throughput.

Prezzi dell'API Storage Write

Per i prezzi, consulta Prezzi dell'importazione dati.

Caso d'uso di esempio

Supponiamo che esista una pipeline che elabora i dati sugli eventi dai log degli endpoint. Gli eventi vengono generati continuamente e devono essere disponibili per le query in BigQuery il prima possibile. Poiché l'aggiornamento dei dati è fondamentale per questo caso d'uso, l'API Storage Write è la scelta migliore per importare i dati in BigQuery. Un'architettura consigliata per mantenere questi endpoint essenziali è l'invio di eventi a Pub/Sub, da dove vengono utilizzati da una pipeline Dataflow in modalità flusso che trasmette direttamente in BigQuery.

Un problema di affidabilità principale per questa architettura è come gestire l'errore di inserimento di un record in BigQuery. Se ogni record è importante e non può essere perso, i dati devono essere memorizzati nella memoria prima di tentare l'inserimento. Nell'architettura consigliata sopra, Pub/Sub può svolgere il ruolo di un buffer con le sue funzionalità di conservazione dei messaggi. La pipeline Dataflow deve essere configurata per riprovare gli inserimenti in streaming di BigQuery con backoff esponenziale troncato. Una volta esaurita la capacità di Pub/Sub come buffer, ad esempio in caso di indisponibilità prolungata di BigQuery o di un errore di rete, i dati devono essere mantenuti nel client e il client deve disporre di un meccanismo per riprendere l'inserimento dei record permanenti una volta ripristinata la disponibilità. Per ulteriori informazioni su come gestire questa situazione, consulta il post del blog Guida all'affidabilità di Google Pub/Sub.

Un altro caso di errore da gestire è quello di un record dannoso. Un record dannoso è un record rifiutato da BigQuery perché non è stato inserito con un errore non ripetibile o un record che non è stato inserito correttamente dopo il numero massimo di tentativi. Entrambi i tipi di record devono essere memorizzati in una "coda di messaggi non recapitati" dalla pipeline di Dataflow per ulteriori accertamenti.

Se sono necessarie le semantiche di esecuzione esattamente una volta, crea uno stream di scrittura in tipo di commit con gli offset dei record forniti dal client. In questo modo vengono evitati i duplicati, poiché l'operazione di scrittura viene eseguita solo se il valore dell'offset corrisponde all'offset di accodamento successivo. Se non fornisci un offset, i record vengono aggiunti alla fine corrente dello stream e la ripetizione di un'aggiunta non riuscita potrebbe comportare la visualizzazione del record più di una volta nello stream.

Se non sono richieste garanzie di esecuzione esattamente una volta, la scrittura nello stream predefinito consente un throughput più elevato e non viene conteggiata ai fini del limite di quota per la creazione di stream di scrittura.

Stima il throughput della tua rete e assicurati in anticipo di disporre di una quota adeguata per gestire il throughput.

Se il tuo carico di lavoro genera o elabora dati a una frequenza molto irregolare, prova a smussare gli eventuali picchi di carico sul client e a trasmettere in streaming in BigQuery con un throughput costante. In questo modo puoi semplificare la pianificazione delle capacità. Se non è possibile, assicurati di essere pronto a gestire gli errori 429 (risorsa esaurita) se e quando il tuo throughput supera la quota durante picchi brevi.

Passaggi successivi