Best practice per il caricamento collettivo

Questa pagina fornisce le linee guida per caricare in modo efficiente grandi quantità di dati in Spanner.

Hai diverse opzioni per il caricamento collettivo dei dati in Spanner:

Sebbene sia possibile anche inserire righe utilizzando Google Cloud CLI, sconsigliamo di utilizzare gcloud CLI per il caricamento collettivo.

Linee guida sulle prestazioni per il caricamento collettivo

Per ottenere prestazioni ottimali di caricamento collettivo, massimizza l'uso del partizionamento per distribuire la scrittura dei dati tra le attività worker.

Spanner utilizza la suddivisione basata sul carico per distribuire uniformemente il carico di dati tra le risorse di calcolo dell'istanza. Dopo alcuni minuti di carico elevato, Spanner introduce confini della suddivisionee tra le righe. In generale, se il carico dei dati è ben distribuito e se segui le best practice per la progettazione dello schema e il caricamento in blocco, la velocità effettiva di scrittura dovrebbe raddoppiare ogni pochi minuti fino a quando le risorse della CPU disponibili nell'istanza non saranno saturate.

Partizione dei dati in base alla chiave primaria

Spanner partiziona dinamicamente le tabelle in intervalli più piccoli. La chiave primaria di una riga determina dove è partizionata.

Per ottenere una velocità effettiva di scrittura ottimale per i caricamenti collettivi, suddividi i dati in base alla chiave primaria con questo pattern:

  • Ogni partizione contiene un intervallo di righe consecutive, come stabilito dalle colonne chiave.
  • Ogni commit contiene dati relativi a una sola partizione.

Consigliamo che il numero delle partizioni sia dieci volte superiore al numero di nodi nell'istanza Spanner. Per assegnare righe alle partizioni:

  • Ordina i dati in base alla chiave primaria.
  • Dividi i dati in 10 * (numero di nodi) separati e di dimensioni uguali.
  • Crea e assegna un'attività worker separata a ciascuna partizione. La creazione delle attività worker avviene nell'applicazione. Non è una funzionalità di Spanner.

Seguendo questo pattern, dovresti vedere una velocità effettiva complessiva massima di scrittura collettiva di 10-20 MB al secondo per nodo per carichi di grandi dimensioni.

Quando carichi i dati, Spanner crea e aggiorna le suddivisioni per bilanciare il carico sui nodi nell'istanza. Durante questo processo, potresti riscontrare cali temporanei della velocità effettiva.

Esempio

Hai una configurazione regionale con tre nodi. Hai 90.000 righe in una tabella senza interleaving. Le chiavi primarie nella tabella sono comprese tra 1 e 90.000.

  • Righe: 90.000 righe
  • Nodi: 3
  • Partizioni: 10 * 3 = 30
  • Righe per partizione: 90.000 / 30 = 3000.

La prima partizione include l'intervallo di chiavi da 1 a 3000. La seconda partizione include l'intervallo di chiavi da 3001 a 6000. La 30a partizione include l'intervallo di chiavi da 87001 a 90000. Non devi utilizzare chiavi sequenziali in una tabella di grandi dimensioni. Questo esempio è solo a scopo dimostrativo.

Ogni attività worker invia le scritture per una singola partizione. All'interno di ogni partizione, devi scrivere le righe in sequenza in base alla chiave primaria. Anche la scrittura casuale di righe rispetto alla chiave primaria dovrebbe fornire una velocità effettiva ragionevolmente elevata. La misurazione delle esecuzioni dei test ti consente di capire quale approccio offre le prestazioni migliori per il tuo set di dati.

Se decidi di non utilizzare le partizioni

La scrittura di righe casuali all'interno di un commit potrebbe essere più lenta rispetto alla scrittura di un insieme contiguo di righe in un commit e probabilmente interessa i dati in partizioni diverse. La latenza di commit e l'overhead sono maggiori quando vengono scritte più suddivisioni in un commit, grazie al maggiore coordinamento tra i server. È probabile che siano coinvolti più segmenti, perché ogni riga casuale potrebbe appartenere a una suddivisione diversa. Nel peggiore dei casi, ogni scrittura coinvolge ogni suddivisione nell'istanza Spanner. Come indicato sopra, la velocità effettiva di scrittura viene ridotta quando sono presenti più suddivisioni.

Caricamento collettivo senza partizionamento

Scrivere un insieme contiguo di righe in un commit può essere più veloce rispetto alla scrittura di righe casuali. Le righe casuali probabilmente includono anche dati di partizioni diverse.

Quando in un commit vengono scritte più partizioni, è necessario un maggiore coordinamento tra i server, aumentando la latenza e l'overhead di commit.

È probabile che siano coinvolte più partizioni perché ogni riga casuale potrebbe appartenere a una partizione diversa. Nel peggiore dei casi, ogni scrittura coinvolge ogni partizione dell'istanza Spanner. Come accennato in precedenza, la velocità effettiva di scrittura diminuisce quando sono coinvolte più partizioni.

Evita il sovraccarico

È possibile inviare più richieste di scrittura di quante ne possa gestire Spanner. Spanner gestisce il sovraccarico interrompendo le transazioni, una procedura chiamata pushback. Per le transazioni di sola scrittura, Spanner ritenta automaticamente la transazione. In questi casi, il pushback si presenta con una latenza elevata. Durante i carichi di lavoro pesanti, il respingimento può durare fino a un minuto. In caso di carichi molto pesanti, la risposta può durare diversi minuti. Per evitare il pushback, devi limitare le richieste di scrittura per mantenere l'utilizzo della CPU entro limiti ragionevoli. In alternativa, gli utenti possono aumentare il numero di nodi in modo che l'utilizzo della CPU rimanga entro i limiti.

Esegui il commit di mutazioni comprese tra 1 e 5 MB alla volta

Ogni scrittura su Spanner comporta un certo overhead, indipendentemente dal fatto che sia grande o piccolo. Per massimizzare la velocità effettiva, massimizza la quantità di dati archiviati per scrittura. Le scritture più grandi riducono il rapporto di overhead per scrittura. Una buona tecnica è far sì che ogni commit modifichi centinaia di righe. Quando si scrivono righe relativamente grandi, una dimensione di commit compresa tra 1 MB e 5 MB offre di solito le prestazioni migliori. Quando si scrivono valori ridotti, o valori indicizzati, generalmente è preferibile scrivere al massimo alcune centinaia di righe in un singolo commit. Indipendentemente dalla dimensione del commit e dal numero di righe, tieni presente che esiste un limite di 80.000 mutazioni per commit. Per determinare le prestazioni ottimali, devi testare e misurare la velocità effettiva.

I commit di dimensioni superiori a 5 MB o a più di alcune centinaia di righe non offrono vantaggi aggiuntivi e rischiano di superare i limiti di Spanner per le dimensioni e le mutazioni del commit per commit.

Linee guida per gli indici secondari

Se il database ha indici secondari, devi scegliere se aggiungerli allo schema del database prima o dopo il caricamento dei dati della tabella.

  • L'aggiunta dell'indice prima del caricamento dei dati consente il completamento immediato della modifica dello schema. Tuttavia, ogni scrittura che interessa l'indice richiede più tempo, perché deve anche aggiornare l'indice. Una volta completato il caricamento, il database è immediatamente utilizzabile con tutti gli indici. Per creare contemporaneamente una tabella e i relativi indici, invia le istruzioni DDL per la nuova tabella e i nuovi indici in una singola richiesta a Spanner.

  • Aggiungere l'indice dopo aver caricato i dati significa che ogni scrittura è efficiente. Tuttavia, la modifica dello schema per ogni backfill dell'indice può richiedere molto tempo. Il database non è completamente utilizzabile e le query non possono utilizzare gli indici finché non sono state completate tutte le modifiche allo schema. Il database può continuare a gestire le scritture e le query, ma a una velocità inferiore.

Ti consigliamo di aggiungere gli indici fondamentali per la tua applicazione aziendale prima di caricare i dati. Per tutti gli indici non critici, aggiungili dopo la migrazione dei dati.

Testare e misurare la velocità effettiva

Prevedere la velocità effettiva può essere difficile. Ti consigliamo di testare la strategia di caricamento collettivo prima di eseguire il caricamento finale. Per un esempio dettagliato di utilizzo del partizionamento e del monitoraggio delle prestazioni, consulta Massimizzare la velocità effettiva di caricamento dei dati.

Best practice per il caricamento collettivo periodico su un database esistente

Se stai aggiornando un database esistente che contiene dati, ma non ha indici secondari, i suggerimenti in questo argomento si applicano comunque.

Se disponi di indici secondari, le istruzioni potrebbero produrre prestazioni ragionevoli. Il rendimento dipende dalla quantità media di divisioni coinvolte nelle transazioni. Se la velocità effettiva scende troppo bassa, puoi provare quanto segue:

  • Includere un numero inferiore di mutazioni in ogni commit, che potrebbe aumentare la velocità effettiva.
  • Se il caricamento è superiore alle dimensioni attuali totali della tabella in fase di aggiornamento, elimina gli indici secondari e aggiungili di nuovo dopo aver caricato i dati. Questo passaggio di solito non è necessario, ma potrebbe migliorare la velocità effettiva.