Best practice per il caricamento collettivo

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

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

Anche se puoi anche inserire righe utilizzando Google Cloud CLI, sconsigliamo di utilizzare gcloud CLI per il caricamento collettivo.

Linee guida sul rendimento per il caricamento collettivo

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

Spanner utilizza la suddivisione basata sul carico per distribuire in modo uniforme il carico dei dati tra le risorse di calcolo dell'istanza. Dopo alcuni minuti di carico elevato, Spanner introduce confini della suddivisione tra le righe. In generale, se il carico dei dati è ben distribuito e segui le best practice per la progettazione dello schema e il caricamento collettivo, la velocità effettiva di scrittura dovrebbe raddoppiare a intervalli di pochi minuti finché non saturano le risorse della CPU disponibili nell'istanza.

Partizionare i 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, partiziona i dati in base alla chiave primaria con questo pattern:

  • Ogni partizione contiene un intervallo di righe consecutive, come determinato dalle colonne delle chiavi.
  • Ogni commit contiene dati solo per una singola partizione.

Ti consigliamo di utilizzare un numero di partizioni pari a dieci volte il numero di nodi nell'istanza Spanner. Per assegnare righe alle partizioni:

  • Ordina i dati per chiave primaria.
  • Dividi i dati in 10 * (numero di nodi) partizioni separate e di pari dimensioni.
  • Crea e assegna un'attività worker separata a ogni partizione. La creazione delle attività worker viene eseguita nell'applicazione. Non è una funzionalità di Spanner.

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

Man mano che carichi i dati, Spanner crea e aggiorna le suddivisioni per bilanciare il carico sui nodi nell'istanza. Durante questa operazione, potresti notare cali temporanei della velocità effettiva.

Esempio

Hai una configurazione a livello di regione con 3 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: 90000 / 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 utilizzare chiavi sequenziali in una tabella di grandi dimensioni. questo esempio è fornito a puro titolo dimostrativo.

Ogni attività worker invia le scritture per una singola partizione. All'interno di ogni partizione, devi scrivere le righe in sequenza per 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 consentirà di capire quale approccio offre le migliori prestazioni per il tuo set di dati.

Se decidi di non usare le partizioni

La scrittura di righe casuali all'interno di un commit potrebbe essere più lenta rispetto alla scrittura di un insieme di righe contigue in un commit e probabilmente interessa i dati in partizioni diverse. La latenza e l'overhead del commit sono superiori quando vengono scritte più suddivisioni in un commit, grazie a un maggiore coordinamento tra i server. È probabile che siano coinvolte più suddivisioni, in quanto ogni riga casuale potrebbe appartenere a una suddivisione diversa. Nel peggiore dei casi, ogni scrittura riguarda ogni suddivisione nell'istanza Spanner. Come indicato in precedenza, la velocità effettiva di scrittura si riduce quando sono coinvolte più suddivisioni.

Caricamento collettivo senza partizionamento

La scrittura di un insieme di righe contigue in un commit può essere più rapida rispetto alla scrittura di righe casuali. È probabile che le righe casuali includano anche dati di partizioni diverse.

Quando in un commit vengono scritte più partizioni, è necessario un maggiore coordinamento tra i server, con un conseguente aumento della latenza e dell'overhead del commit.

Sono probabilmente coinvolte più partizioni perché ogni riga casuale potrebbe appartenere a una partizione diversa. Nel peggiore dei casi, ogni scrittura riguarda ogni partizione dell'istanza Spanner. Come accennato in precedenza, la velocità effettiva di scrittura si riduce quando sono coinvolte più partizioni.

Evita sovraccarichi

È possibile inviare più richieste di scrittura di quelle che Spanner può gestire. Spanner gestisce l'overload interrompendo le transazioni, ovvero il cosiddetto pushback. Per le transazioni di sola scrittura, Spanner ripete automaticamente la transazione. In questi casi, il pushback viene mostrato con latenza elevata. In condizioni di carico intenso, il pushback può durare fino a un minuto. In caso di carichi molto pesanti, il pushback può durare diversi minuti. Per evitare il respingimento, 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 tra 1 MB e 5 MB di mutazioni alla volta

Ogni scrittura su Spanner contiene un sovraccarico, 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 è che ogni commit modifica centinaia di righe. Quando scrivi righe relativamente grandi, una dimensione di commit compresa tra 1 e 5 MB fornisce in genere le prestazioni migliori. Quando scrivi valori di piccole dimensioni o che vengono indicizzati, è generalmente consigliabile 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 più di alcune centinaia di righe non offrono vantaggi aggiuntivi e rischiano di superare i limiti di Spanner relativi alle dimensioni del commit e alle mutazioni 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 di completare immediatamente la modifica dello schema. Tuttavia, ogni scrittura che interessa l'indice richiede più tempo, in quanto richiede anche l'aggiornamento dell'indice. Al termine del caricamento dei dati, il database è immediatamente utilizzabile con tutti gli indici. Per creare una tabella e i relativi indici contemporaneamente, invia le istruzioni DDL per la nuova tabella e i nuovi indici in un'unica 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 vengono completate tutte le modifiche allo schema. Il database può comunque gestire scritture e query, ma a una velocità inferiore.

Ti consigliamo di aggiungere gli indici fondamentali per l'applicazione aziendale prima di caricare i dati. Aggiungi tutti gli indici non critici dopo la migrazione dei dati.

Testa e misura la velocità effettiva

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

Best practice per il caricamento in blocco periodico in 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 generare un rendimento ragionevole. Il rendimento dipende dal numero medio di segmenti interessati alle transazioni. Se la velocità effettiva scende troppo, puoi provare quanto segue:

  • Includi un numero inferiore di mutazioni in ogni commit, il che potrebbe aumentare la velocità effettiva.
  • Se il caricamento supera le dimensioni totali correnti della tabella da aggiornare, 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.