Best practice per l'API BigQuery Storage Scrivi

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

Limitare la frequenza di creazione dello stream

Prima di creare uno stream, valuta se puoi utilizzare lo stream predefinito. Per gli scenari in modalità flusso, il flusso predefinito ha meno limiti di quota e può scalare meglio rispetto all'utilizzo di flussi di dati creati dall'applicazione. Se utilizzi un flusso creato dall'applicazione, assicurati di utilizzare la velocità effettiva massima su ogni flusso prima di crearne altri. Ad esempio, utilizza le scritture asincrone.

Per i flussi creati dall'applicazione, evita di chiamare CreateWriteStream ad alta frequenza. In genere, se superi le 40-50 chiamate al secondo, la latenza delle chiamate API aumenta notevolmente (>25 s). Assicurati che la tua applicazione possa accettare un avvio a freddo e incrementare gradualmente il numero di stream, nonché limitare la frequenza delle chiamate CreateWriteStream. Potresti anche impostare una scadenza maggiore per attendere il completamento della chiamata, in modo che non vada a buon fine con un errore DeadlineExceeded. Esiste anche una quota a lungo termine sulla tariffa massima di CreateWriteStream chiamate. La creazione di flussi di dati è un processo che richiede molte risorse; pertanto, ridurre la frequenza di creazione dei flussi e utilizzare completamente 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 nel flusso predefinito, ma solo una singola connessione attiva sui flussi creati dall'applicazione.

Quando utilizzi il flusso predefinito, puoi utilizzare il multiplexing dell'API Storage Scrivi per scrivere su più tabelle di destinazione con connessioni condivise. Connessioni dei pool di multiplexing per una migliore velocità effettiva e utilizzo delle risorse. Se il 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 sull'implementazione di Go, consulta Condivisione delle connessioni (multiplexing). Se utilizzi il connettore Beam con semantica "at-least-once", puoi abilitare il multiplexing tramite UseStorageApiConnectionPool. Il connettore Spark di Dataproc ha il multiplexing abilitato per impostazione predefinita.

Per ottenere prestazioni ottimali, utilizza una connessione per il maggior numero possibile di scritture di dati. Non utilizzare un'unica connessione per una singola scrittura o apri e chiudi flussi di dati per molte scritture di piccole dimensioni.

Esiste una quota per il numero di connessioni simultanee che possono essere aperte contemporaneamente per progetto. Oltre il limite, le chiamate al numero AppendRows non andranno a buon fine. Tuttavia, la quota per le connessioni simultanee può essere aumentata e di solito non dovrebbe essere un fattore limitante per la scalabilità.

Ogni chiamata a AppendRows crea un nuovo oggetto writer. Pertanto, quando si utilizza un flusso creato dall'applicazione, il numero di connessioni corrisponde al numero di flussi di dati creati. In genere, una singola connessione supporta almeno 1 Mbps di velocità effettiva. 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.

È prevista anche una quota per la velocità effettiva totale per progetto. Rappresenta i byte al secondo in tutte le connessioni che passano attraverso il servizio API StorageWrite. Se il progetto supera questa quota, puoi richiedere un limite di quota più elevato. In genere ciò comporta l'aumento delle quote di accompagnamento, ad esempio la quota per le connessioni simultanee, in un rapporto uguale.

Gestisci gli offset dei flussi per ottenere una semantica "exactly-once"

L'API StorageWrite consente solo le scritture fino alla fine attuale del flusso, che si sposta man mano che vengono aggiunti i dati. La posizione corrente nel flusso è specificata come offset dall'inizio.

Quando scrivi in un flusso creato dall'applicazione, puoi specificare l'offset del flusso per ottenere una semantica "exactly-once".

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

  • ALREADY_EXISTS (StorageErrorCode.OFFSET_ALREADY_EXISTS): la riga è già stata scritta. Puoi tranquillamente 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 un valore di offset errato, quindi devi gestire gli offset con attenzione.

Prima di utilizzare gli offset di flusso, valuta se è necessaria la semantica "exactly-once". Ad esempio, se la pipeline di dati upstream garantisce solo le scritture "Almeno una volta" o se riesci a rilevare facilmente i duplicati dopo l'importazione dati, potresti non richiedere scritture "exactly-once". In tal caso, consigliamo di utilizzare il flusso predefinito, che non richiede il monitoraggio degli offset di riga.

Non bloccare per le chiamate AppendRows.

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

Gestire gli aggiornamenti dello schema

Per gli scenari di flussi di dati, gli schemi delle tabelle vengono in genere gestiti al di fuori della pipeline di flusso. Capita spesso che lo schema si evolva nel tempo, ad esempio aggiungendo nuovi campi con valori null. Una pipeline affidabile deve gestire gli aggiornamenti dello schema fuori banda.

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

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

Per inviare nuovi campi nel payload, devi prima aggiornare lo schema della tabella in BigQuery. L'API StorageWrite rileva le modifiche allo schema dopo un breve lasso di tempo, nell'ordine dei minuti. Quando l'API StorageWrite 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 aprirne di nuove 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 con lo schema aggiornato. Non è necessario chiudere e riaprire la connessione in modo esplicito. Per verificare le modifiche allo schema in modo programmatico, chiama AppendRowsResponse.hasUpdatedSchema dopo il completamento del metodo append.

Puoi anche configurare JsonStreamWriter in modo che ignori i campi sconosciuti nei dati di input. Per impostare questo comportamento, chiama setIgnoreUnknownFields. Questo comportamento è simile a quello dell'opzione ignoreUnknownValues quando si utilizza l'API tabledata.insertAll legacy. Tuttavia, può causare una perdita involontaria di dati, perché i campi sconosciuti vengono eliminati in modalità silenziosa.