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, consulta la Panoramica dell'API BigQuery Storage Write.

Limitare la frequenza di creazione degli stream

Prima di creare uno stream, valuta se puoi utilizzare lo stream predefinito. Per gli scenari di streaming, lo stream predefinito presenta meno limitazioni di quota e può essere scalato meglio rispetto all'utilizzo di stream creati dall'applicazione. Se utilizzi uno stream creato dall'applicazione, assicurati di utilizzare la larghezza di banda massima su ogni stream prima di creare stream aggiuntivi. Ad esempio, utilizza le scritture asincrone.

Per gli stream creati dall'applicazione, evita di chiamare CreateWriteStream con frequenza elevata. In genere, se superi 40-50 chiamate al secondo, la latenza delle chiamate API aumenta notevolmente (>25 s). Assicurati che l'applicazione possa accettare un inizio a freddo e aumentare gradualmente il numero di stream e limitare la frequenza delle chiamateCreateWriteStream. Puoi anche impostare una scadenza più lunga per attendere il completamento della chiamata, in modo che non venga interrotta con un errore DeadlineExceeded. Esiste anche una quota a lungo termine per la frequenza massima di chiamate CreateWriteStream. La creazione di stream è un processo che richiede molte risorse, quindi ridurre la frequenza di creazione degli stream e utilizzare al meglio 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 nello stream predefinito, ma solo una connessione attiva negli stream creati dall'applicazione.

Quando utilizzi lo stream predefinito, puoi utilizzare il multiplexing dell'API Storage Write per scrivere in più tabelle di destinazione con connessioni condivise. Il multiplexing raggruppa le connessioni per migliorare il throughput e l'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 sull'implementazione in Java, consulta Utilizzare il multiplexing. Per i dettagli sull'implementazione di Go, consulta Condivisione della connessione (multiplexing). Se utilizzi il connettore Beam con la semantica almeno una volta, puoi attivare il multiplexing tramite UseStorageApiConnectionPool. Il connettore Dataproc Spark ha il multiplexing abilitato per impostazione predefinita.

Per ottenere le migliori prestazioni, 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. Superato il limite, le chiamate a AppendRows non vanno a buon fine. Tuttavia, la quota per le connessioni simultanee può essere aumentata e in genere non dovrebbe essere un fattore limitante per il ridimensionamento.

Ogni chiamata a AppendRows crea un nuovo oggetto DataWriter. Pertanto, quando utilizzi uno stream creato dall'applicazione, il numero di connessioni corrisponde al numero di stream che sono stati 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 MB/s.

Esiste anche una quota per il throughput totale per progetto. Questi rappresentano i byte al secondo su tutte le connessioni che passano attraverso il servizio API Storage Write. Se il tuo progetto supera questa quota, puoi richiedere un limite di quota più alto. In genere, questo comporta l'aumento delle quote aggiuntive, come la quota di connessioni simultanee, in una proporzione uguale.

Gestire gli offset dello stream per ottenere la semantica esatta

L'API Storage Write consente le scritture solo all'estremità corrente dello stream, che si sposta man mano che i dati vengono aggiunti. La posizione corrente nello stream è specificata come offset dall'inizio dello stream.

Quando scrivi in uno stream creato dall'applicazione, puoi specificare l'offset dello stream per ottenere la semantica di scrittura esattamente una volta.

Quando specifichi un offset, l'operazione di scrittura è idempotente, il che consente di eseguire nuovamente il tentativo in caso di errori di rete o mancata risposta del server. Gestisci i seguenti errori relativi agli offset:

  • ALREADY_EXISTS (StorageErrorCode.OFFSET_ALREADY_EXISTS): la riga è stata già 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 dell'offset errato, quindi devi gestire attentamente gli offset.

Prima di utilizzare gli offset dello stream, valuta se hai bisogno della semantica esattamente una volta. Ad esempio, se la pipeline di dati a monte garantisce solo scritture almeno una volta o se puoi rilevare facilmente i duplicati dopo l'importazione dati, potresti non richiedere scritture esattamente una volta. In questo caso, ti consigliamo di utilizzare lo stream predefinito, che non richiede il monitoraggio degli offset di riga.

Non bloccare le chiamate 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 le richieste sono state inserite in coda. Per la massima velocità in uscita, chiama AppendRows senza bloccarti in 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 con l'aggiunta di nuovi campi con valori null. Una pipeline solida deve gestire gli aggiornamenti dello schema out-of-band.

L'API Storage Write supporta gli schemi di tabella come segue:

  • La prima richiesta di scrittura include lo schema.
  • Invii ogni riga di dati come buffer di protocollo binario. BigQuery mappa i dati allo schema.
  • Puoi omettere i campi con valori null, ma non puoi includere campi non presenti nello schema corrente. 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 poco tempo, nell'ordine di pochi 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 i 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 la presenza di modifiche allo schema in modo programmatico, chiama AppendRowsResponse.hasUpdatedSchema al termine del metodo append.

Puoi anche configurare JsonStreamWriter in modo da 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 precedente tabledata.insertAll. Tuttavia, può comportare la perdita involontaria di dati, poiché i campi sconosciuti vengono eliminati silenziosamente.