Best practice per l'API BigQuery Storage Write

Questo documento fornisce le best practice per l'utilizzo dell'API BigQuery Storage Write. Prima di leggere questo documento, leggi Panoramica dell'API BigQuery Storage Write.

Limitare la velocità di creazione degli stream

Prima di creare un flusso, valuta se puoi utilizzare il flusso predefinito. Per gli scenari di streaming, lo stream predefinito ha meno limitazioni di quota e può essere scalato meglio rispetto all'utilizzo di stream creati dall'applicazione. Se utilizzi un flusso creato dall'applicazione, assicurati di utilizzare il throughput massimo su ogni flusso prima di creare flussi aggiuntivi. Ad esempio, utilizza scritture asincrone.

Per gli stream creati dalle applicazioni, evita di chiamare CreateWriteStream con una frequenza elevata. In genere, se superi le 40-50 chiamate al secondo, la latenza delle chiamate API aumenta notevolmente (> 25 secondi). Assicurati che la tua applicazione possa accettare un avvio a freddo e aumenti gradualmente il numero di stream e limiti la frequenza di chiamate CreateWriteStream. Puoi anche impostare una scadenza più lunga per attendere il completamento della chiamata, in modo che non si verifichi un errore DeadlineExceeded. Esiste anche una quota a lungo termine sulla velocità massima di CreateWriteStream chiamate. La creazione di stream è un processo che richiede molte risorse, quindi ridurre la velocità di creazione degli stream e utilizzare appieno quelli esistenti è il modo migliore per non superare questo limite.

Gestione del pool di connessioni

Il metodo AppendRows crea una connessione bidirezionale a uno stream. Puoi aprire più connessioni sullo stream predefinito, ma solo una connessione attiva sugli stream creati dall'applicazione.

Quando utilizzi il flusso predefinito, puoi utilizzare il multiplexing dell'API Storage Write per scrivere in più tabelle di destinazione con connessioni condivise. Multiplexing delle connessioni dei pool per una migliore velocità effettiva e utilizzo delle risorse. Se il tuo flusso di lavoro ha più di 20 connessioni simultanee, ti consigliamo di utilizzare il multiplexing. Il multiplexing è disponibile in Java e Go. Per i dettagli di implementazione di Java, consulta Utilizzare il multiplexing. Per i dettagli dell'implementazione di Go, vedi Condivisione della connessione (multiplexing). Se utilizzi il connettore Beam con semantica at-least-once, puoi attivare il multiplexing tramite UseStorageApiConnectionPool. Il connettore Dataproc Spark ha il multiplexing attivato per impostazione predefinita.

Per ottenere le prestazioni migliori, utilizza una connessione per il maggior numero possibile di scritture di dati. Non utilizzare una connessione per una sola scrittura o aprire e chiudere stream per molte piccole scritture.

Esiste una quota per il numero di connessioni simultanee che possono essere aperte contemporaneamente per progetto. Al di sopra del limite, le chiamate a AppendRows non vanno a buon fine. Tuttavia, la quota per le connessioni simultanee può essere aumentata e normalmente non dovrebbe essere un fattore limitante per lo scaling.

Ogni chiamata a AppendRows crea un nuovo oggetto writer di dati. Pertanto, quando utilizzi un flusso creato dall'applicazione, il numero di connessioni corrisponde al numero di flussi creati. In genere, una singola connessione supporta almeno 1 MBps di throughput. Il limite superiore dipende da diversi fattori, come la larghezza di banda della rete, lo schema dei dati e il carico del server, ma può superare i 10 MBps.

Esiste anche una quota per il throughput totale per progetto. Questo valore rappresenta i byte al secondo in tutte le connessioni che passano attraverso il servizio API Storage Write. Se il tuo progetto supera questa quota, puoi richiedere un aggiustamento della quota. In genere, ciò comporta l'aumento delle quote associate, come la quota di connessioni simultanee, in un rapporto uguale.

Gestire gli offset dello stream per ottenere la semantica exactly-once

L'API Storage Write consente solo di scrivere alla fine corrente dello stream, che si sposta man mano che vengono aggiunti dati. La posizione corrente nel flusso viene specificata come offset dall'inizio del flusso.

Quando scrivi in un flusso creato dall'applicazione, puoi specificare l'offset del flusso per ottenere una semantica di scrittura esattamente una volta.

Quando specifichi un offset, l'operazione di scrittura è idempotente, il che rende sicuro riprovare a causa di errori di rete o mancata risposta del server. Gestisci i seguenti errori relativi agli offset:

  • ALREADY_EXISTS (StorageErrorCode.OFFSET_ALREADY_EXISTS): la riga era già stata scritta. Puoi ignorare questo errore.
  • OUT_OF_RANGE (StorageErrorCode.OFFSET_OUT_OF_RANGE): un'operazione di scrittura precedente non è riuscita. Riprova dall'ultima scrittura riuscita.

Tieni presente che questi errori possono verificarsi anche se imposti il valore di offset errato, quindi devi gestire gli offset con attenzione.

Prima di utilizzare gli offset di flusso, valuta se hai bisogno di una semantica di tipo exactly-once. Ad esempio, se la pipeline di dati upstream garantisce solo scritture at-least-once o se puoi rilevare facilmente i duplicati dopo l'importazione dati, potresti non aver bisogno di scritture exactly-once. In questo caso, ti consigliamo di utilizzare lo stream predefinito, che non richiede di tenere traccia degli offset di riga.

Non bloccare le chiamate su AppendRows

Il metodo AppendRows è asincrono. Puoi inviare una serie di scritture senza bloccare una risposta per ogni scrittura singolarmente. I messaggi di risposta sulla connessione bidirezionale arrivano nello stesso ordine in cui sono state accodate le richieste. Per ottenere la massima velocità effettiva, chiama AppendRows senza bloccare l'attesa della risposta.

Gestire gli aggiornamenti dello schema

Per gli scenari di streaming dei dati, gli schemi delle tabelle vengono in genere gestiti al di fuori della pipeline di streaming. È normale che lo schema si evolva nel tempo, ad esempio aggiungendo nuovi campi che accettano valori null. Una pipeline solida deve gestire gli aggiornamenti dello schema fuori banda.

L'API Storage Write supporta gli schemi delle tabelle nel seguente modo:

  • La prima richiesta di scrittura include lo schema.
  • Ogni riga di dati viene inviata come buffer di protocollo binario. BigQuery mappa i dati allo schema.
  • Puoi omettere i campi nullabili, ma non puoi includere campi non presenti nello schema attuale. Se invii righe con campi aggiuntivi, l'API Storage Write restituisce un StorageError con StorageErrorCode.SCHEMA_MISMATCH_EXTRA_FIELD.

Se vuoi inviare nuovi campi nel payload, devi prima aggiornare lo schema della tabella in BigQuery. L'API Storage Write rileva le modifiche allo schema dopo un breve periodo di tempo, nell'ordine di minuti. Quando l'API Storage Write rileva la modifica dello schema, il messaggio di risposta AppendRowsResponse contiene un oggetto TableSchema che descrive il nuovo schema.

Per inviare dati utilizzando lo schema aggiornato, devi chiudere le connessioni esistenti e aprire nuove connessioni con il nuovo schema.

Client Java. La libreria client Java fornisce alcune funzionalità aggiuntive per gli aggiornamenti dello schema tramite la classe JsonStreamWriter. Dopo un aggiornamento dello schema, JsonStreamWriter si riconnette automaticamente allo schema aggiornato. Non è necessario chiudere e riaprire esplicitamente la connessione. Per verificare le modifiche allo schema a livello di programmazione, chiama AppendRowsResponse.hasUpdatedSchema dopo il completamento del metodo append.

Puoi anche configurare JsonStreamWriter per ignorare i campi sconosciuti nei dati di input. Per impostare questo comportamento, chiama setIgnoreUnknownFields. Questo comportamento è simile all'opzione ignoreUnknownValues quando si utilizza l'API tabledata.insertAll legacy. Tuttavia, può causare la perdita involontaria di dati, perché i campi sconosciuti vengono eliminati automaticamente.