Recensione di CockroachDB: un database SQL scalabile creato per la sopravvivenza

Fino a poco tempo fa, quando cercavi un database dovevi scegliere: scalabilità o coerenza? I database SQL come MySQL garantiscono una forte coerenza, ma non scalano bene in orizzontale. (Il partizionamento orizzontale manuale per la scalabilità non è un'idea divertente di nessuno.) I database NoSQL come MongoDB si adattano magnificamente, ma offrono solo consistenza finale. ("Aspetta abbastanza a lungo e potrai leggere la risposta giusta", il che non è in alcun modo per eseguire transazioni finanziarie.)

Google Cloud Spanner, un servizio di database relazionale completamente gestito in esecuzione su Google Compute Engine (GCE) rilasciato a febbraio 2017, ha la scalabilità dei database NoSQL pur mantenendo la compatibilità SQL, gli schemi relazionali, le transazioni ACID e una forte coerenza esterna. Spanner è un database relazionale frammentato, distribuito a livello globale e replicato che utilizza un algoritmo Paxos per raggiungere un consenso tra i suoi nodi.

Un'alternativa a Spanner e oggetto di questa recensione è CockroachDB, un database SQL distribuito open source e scalabile orizzontalmente sviluppato da ex googler che avevano familiarità con Spanner. CockroachDB prende in prestito da Spanner di Google per la progettazione del suo sistema di archiviazione dati e utilizza un algoritmo Raft per raggiungere un consenso tra i suoi nodi.

Come Cloud Spanner, CockroachDB è un database SQL distribuito costruito su un archivio di valori-chiave transazionale e coerente, nel caso di CockroachDB su RocksDB. Gli obiettivi di progettazione principali di CockroachDB sono il supporto per le transazioni ACID, la scalabilità orizzontale e (soprattutto) la sopravvivenza, da cui il nome.

CockroachDB è progettato per resistere a guasti del disco, della macchina, del rack e persino del datacenter con interruzioni di latenza minime e nessun intervento manuale. Ovviamente, per ottenere ciò è necessario eseguire un cluster di molte istanze dei nodi simmetrici di CockroachDB, utilizzando più dischi, macchine, rack e data center.

A differenza di Cloud Spanner, che utilizza l'API TrueTime disponibile per la sincronizzazione dell'ora nei data center di Google, CockroachDB non può contare sulla presenza di orologi atomici e orologi satellitari GPS per sincronizzare l'ora con precisione tra nodi e data center. Ciò ha una serie di implicazioni. Per cominciare, Google TrueTime fornisce un limite superiore per gli offset di clock tra i nodi in un cluster di sette millisecondi. È abbastanza piccolo che un nodo Spanner attende solo sette millisecondi dopo una scrittura prima di segnalare il commit di una transazione, per garantire la coerenza esterna.

Senza TrueTime o una funzione simile, CockroachDB deve tornare a NTP, che fornisce limiti superiori alla sincronizzazione dell'orologio tra 100 millisecondi e 250 millisecondi. Data la finestra temporale più ampia, CockroachDB non attende dopo la scrittura. Invece a volte attende prima di leggere, in pratica riavviando una transazione se legge un valore con un timestamp maggiore dell'inizio della transazione, ancora una volta per garantire la coerenza.

Quando tutti i nodi in un cluster CockroachDB hanno i piccoli limiti superiori per gli offset dell'orologio che puoi ottenere dal GPS o dagli orologi atomici, che è qualcosa che sta diventando disponibile sui principali cloud pubblici, può avere senso eseguirli con la --linearizable bandiera. Ciò li fa aspettare l'offset massimo dell'orologio prima di restituire un commit riuscito, proprio come Spanner.

Come funziona CockroachDB

Ogni nodo CockroachDB è costituito da cinque livelli:

  • SQL, che traduce le query SQL del client in operazioni chiave-valore
  • Transazione, che consente modifiche atomiche a più voci di valori-chiave
  • Distribuzione, che presenta intervalli di valori-chiave replicati come un'unica entità
  • Replica, che replica costantemente e in modo sincrono intervalli di valori-chiave su molti nodi e consente letture coerenti tramite lease
  • Archiviazione, che scrive e legge i dati dei valori-chiave su disco

Il livello SQL analizza le query rispetto a un file Yacc e le trasforma in un albero di sintassi astratto. Dall'albero della sintassi astratta, CockroachDB genera un albero di nodi del piano, che contengono codice valore-chiave. I nodi del piano vengono quindi eseguiti, comunicando con il livello della transazione.

Il livello di transazione implementa la semantica di transazione ACID con commit a due fasi nell'intero cluster, comprese le transazioni cross-range e cross-table, trattando le singole istruzioni come transazioni (chiamata anche modalità di commit automatico). Il commit in due fasi viene eseguito registrando record di transazione e intenti di scrittura, eseguendo operazioni di lettura e trattando eventuali intenti di scrittura riscontrati come conflitti di transazione.

Il livello di distribuzione riceve le richieste dal livello di transazione sullo stesso nodo. Quindi identifica i nodi che dovrebbero ricevere la richiesta e la invia al livello di replica del nodo appropriato.

Il livello di replica copia i dati tra i nodi e garantisce la coerenza tra queste copie implementando un algoritmo di consenso Raft. È possibile controllare il fattore di replica a livello di cluster, database e tabella utilizzando le zone di replica. L'algoritmo di consenso viene utilizzato solo per le scritture e richiede che un quorum di repliche concordi su eventuali modifiche a un intervallo prima che tali modifiche vengano applicate.

Il livello di archiviazione memorizza i dati come coppie chiave-valore su disco utilizzando RocksDB. CockroachDB fa molto affidamento sul controllo della concorrenza multi-versione (MVCC) per elaborare le richieste simultanee e garantire la coerenza. Gran parte di questo lavoro viene svolto utilizzando i timestamp HLC (Hybrid Logic Clock).

Come Spanner, CockroachDB supporta le query sui viaggi nel tempo (abilitate da MVCC). Questi possono risalire fino alla più recente garbage collection del database, eseguita per impostazione predefinita su base giornaliera.

Installazione e utilizzo di CockroachDB

CockroachDB funziona su sistemi operativi Mac, Linux e Windows, almeno per lo sviluppo e il test. I database di produzione Cockroach di solito vengono eseguiti su VM Linux o contenitori orchestrati, spesso ospitati su cloud pubblici in più data center. Il file binario Windows di CockroachDB è ancora in una fase beta e non è consigliato per la produzione, e Apple non produce più hardware per server.

Cockroach Labs

Come puoi vedere nello screenshot qui sopra, ci sono quattro opzioni per l'installazione di CockroachDB su un Mac. Ho scelto Homebrew come probabilmente il più semplice dei quattro.

A proposito, Cockroach Labs pubblica un avviso sul sito che dice che eseguire un'applicazione con stato come CockroachDB in Docker è complicato, non consigliato per le distribuzioni di produzione e per utilizzare uno strumento di orchestrazione come Kubernetes o Docker Swarm per eseguire invece un cluster. Discuterò le opzioni di orchestrazione del contenitore nella sezione successiva.

L'installazione su un Mac è facile brew install cockroachcome mostrato sopra. Nel mio caso, l'aggiornamento automatico di Homebrew ha richiesto molto più tempo (tempo sufficiente per preparare il tè) rispetto all'effettiva installazione di CockroachDB, che ha richiesto solo pochi secondi.

Una volta installato CockroachDB, è abbastanza facile avviare un cluster locale, sebbene vi sia il passaggio aggiuntivo di generare certificati di sicurezza con il cockroach certcomando se si desidera che il cluster sia sicuro. Dopo aver eseguito un cluster (utilizzando il cockroach startcomando una volta per ogni nodo, con i nodi successivi impostati per unirsi al cluster del primo nodo), è possibile connettersi alla pagina di amministrazione Web su qualsiasi nodo con un browser e utilizzare il cockroach sqlclient incorporato per inviare SQL query a qualsiasi nodo. La maggior parte dei browser si lamenterà dei siti con certificati generati da CockroachDB, ma dovresti essere in grado di fare clic su quel terribile avviso e continuare con il sito.

Le impostazioni di produzione consigliate da CockroachDB sono diverse dai valori predefiniti, che sono stati impostati per le istanze di sviluppo e test. Puoi sviluppare su un cluster a un nodo, se lo desideri. Per la produzione, dovresti avere un minimo di tre nodi, eseguire ogni nodo su una macchina, VM o contenitore separato e fornire a ogni istanza cache e memoria SQL aggiuntive. Le impostazioni predefinite sono 128 MB ciascuna per cache e memoria SQL; le impostazioni di produzione consigliate sono di fornire ogni 25 percento di RAM:

cockroach start --cache=25% --max-sql-memory=25%

Più nodi esegui, migliore sarà la resilienza. Più grandi e veloci sono i nodi, migliori sono le prestazioni. Se desideri avere nodi con prestazioni più o meno paragonabili ai nodi di Google Cloud Spanner, che forniscono 2.000 scritture al secondo e 10.000 letture al secondo, allora vorresti qualcosa come le istanze n1-highcpu-8 di GCE, che hanno otto CPU e 8 GB di RAM , con dischi SSD locali (anziché dischi rotanti).

Più distribuisci i tuoi nodi a diversi data center, meglio puoi garantire l'immunità ai guasti a livello di data center. Tuttavia, c'è un costo: la latenza di andata e ritorno tra i data center avrà un effetto diretto sulle prestazioni del database, con i cluster cross-continent che si comportano notevolmente peggiori dei cluster in cui tutti i nodi sono geograficamente vicini tra loro.

Cockroach Labs fornisce istruzioni dettagliate per la distribuzione su AWS, Digital Ocean, GCE e Azure. Le configurazioni consigliate utilizzano bilanciatori del carico, servizi di bilanciamento del carico gestiti nativi o bilanciatori del carico open source come HAProxy.

L'orchestrazione può ridurre l'overhead operativo di un cluster CockroachDB quasi a zero. Cockroach Labs documenta come eseguire questa operazione per la produzione con Kubernetes e Docker Swarm. Il repository CockroachDB-CloudFormation su GitHub mostra come utilizzare AWS CloudFormation e Kubernetes in un'unica zona di disponibilità per lo sviluppo e il test. Adattarlo per la produzione comporterebbe la modifica del modello CloudFormation per utilizzare più zone di disponibilità.

Programmazione e test di CockroachDB

CockroachDB supporta il protocollo cablato PostgreSQL, quindi scrivi il tuo codice come se stessi programmando con Postgres, o almeno un sottoinsieme di Postgres. Questa pagina elenca i driver testati per vari binding di linguaggi di programmazione, inclusi i linguaggi lato server più diffusi. Questa pagina elenca esempi in 10 linguaggi di programmazione e cinque ORM. Non ho riscontrato grosse sorprese quando ho letto il codice, anche se ho individuato alcuni probabili bug minori negli elenchi all'interno della documentazione. Puoi anche eseguire il tuo SQL utilizzando il client interattivo integrato cockroachnell'eseguibile.

Sebbene esista un repository dedicato ai generatori di carico CockroachDB e un altro per i test delle prestazioni, il benchmarking dei cluster CockroachDB non è facile, soprattutto se stai cercando di confrontare CockroachDB con altri database in modo significativo. Un problema è che la rete tra i nodi può essere il passaggio limitante la velocità nei cluster CockroachDB.

Un altro fatto da tenere in considerazione è che la maggior parte dei database SQL convenzionali non viene eseguita in modalità di isolamento SERIALIZZABILE per impostazione predefinita; invece usano una modalità meno rigorosa con prestazioni migliori. CockroachDB utilizza la modalità di isolamento serializzabile per impostazione predefinita. Inoltre, sarebbe un po 'ingiusto testare le prestazioni del join SQL di CockroachDB, che è ancora un work in progress, con la suite TPC-C.

Eppure puoi facilmente vedere la potenza operativa di CockroachDB. Ad esempio, molti database devono essere arrestati e riavviati per ridimensionarli. L'aggiunta di nodi sotto carico in CockroachDB è un gioco da ragazzi, soprattutto se stai utilizzando uno strumento di orchestrazione. Ad esempio, lo screenshot qui sopra mostra i comandi per modificare e visualizzare i nodi in un cluster Kubernetes e lo screenshot qui sotto mostra il cluster monitorato quando i nodi vengono aggiunti. Uno strumento di generazione del carico è stato eseguito continuamente durante tutto il processo.

Una dimostrazione ancora più impressionante mostra la migrazione automatica cross-cloud all'interno di un cluster CockroachDB. Richiede davvero video per rendergli giustizia; il video è ospitato nel post del blog collegato.

CockroachDB SQL 

SQL in CockroachDB è più o meno standard, a differenza di SQL in Cloud Spanner, che utilizza una sintassi non standard per la manipolazione dei dati. Tuttavia, in CockroachDB SQL mancano ancora molte funzionalità.

Ad esempio, la V1.1 non dispone del supporto JSON, previsto per la V1.2. Manca anche l'analisi XML, che non è sulla tabella di marcia. Manca di cascate a livello di riga, pianificate per V1.2, e manca di cursori e trigger, che non sono sulla tabella di marcia. Gli indici geospaziali sono aggiunte "potenziali" che potrebbero arrivare alla roadmap in futuro.

In particolare, l'implementazione iniziale di CockroachDB dei join SQL nel 2016 era volutamente semplicistica e mostrava un ridimensionamento quadratico, rendendolo inutile per interrogare set di dati di grandi dimensioni. La versione in V1.0, realizzata da uno studente cooperativo, implementava hash join, facendo scalare linearmente molte operazioni di join; che ha portato CockroachDB al livello di SQLite. A un certo punto nel 2018, dato un recente round di finanziamento, CockroachDB dovrebbe avere prestazioni di join che si ridimensionano in modo più simile ai join PostgreSQL, così come l'elaborazione di join SQL distribuita sul cluster.