CockroachDB granskning: En skalbar SQL-databas byggd för överlevnad

Fram till nyligen, när du handlade efter en databas, var du tvungen att välja: Skalbarhet eller konsistens? SQL-databaser som MySQL garanterar stark konsistens, men skalas inte bra horisontellt. (Manuell skärning för skalbarhet är ingen idé om roligt.) NoSQL-databaser som MongoDB skalar vackert, men erbjuder bara eventuell konsistens. ("Vänta tillräckligt länge, så kan du läsa rätt svar" - vilket inte är något sätt att göra finansiella transaktioner.)

Google Cloud Spanner, en fullständigt hanterad relationsdatabastjänst som körs på Google Compute Engine (GCE) som släpptes i februari 2017, har skalbarhet av NoSQL-databaser samtidigt som SQL-kompatibilitet, relationsscheman, ACID-transaktioner och stark extern konsistens bibehålls. Spanner är en splittrad, globalt distribuerad och replikerad relationsdatabas som använder en Paxos-algoritm för att nå enighet mellan sina noder.

Ett alternativ till Spanner, och föremålet för denna recension, är CockroachDB, en öppen källkod, horisontellt skalbar distribuerad SQL-databas utvecklad av ex-Googlers som var bekanta med Spanner. CockroachDB lånar från Googles Spanner för design av dess datalagringssystem, och det använder en Raft-algoritm för att nå enighet mellan sina noder.

Liksom Cloud Spanner är CockroachDB en distribuerad SQL-databas byggd ovanpå en transaktionell och konsekvent nyckelvärdesbutik, i CockroachDB: s fall på RocksDB. CockroachDB: s primära designmål är stöd för ACID-transaktioner, horisontell skalbarhet och (mest av allt) överlevnad, därav namnet.

CockroachDB är utformad för att överleva skiv-, maskin-, rack- och till och med datacenterfel med minimal latensstörning och utan manuell intervention. Naturligtvis, för att åstadkomma det måste du köra ett kluster av många instanser av CockroachDBs symmetriska noder, med flera skivor, maskiner, rack och datacenter.

Till skillnad från Cloud Spanner, som använder TrueTime API tillgängligt för tidssynkronisering i Googles datacenter, kan CockroachDB inte räkna med närvaron av atomklockor och GPS-satellitklockor för att synkronisera tiden exakt mellan noder och datacenter. Det har ett antal konsekvenser. Till att börja med ger Google TrueTime en övre gräns för klockförskjutningar mellan noder i ett kluster på sju millisekunder. Det är tillräckligt litet för att en Spanner-nod bara väntar sju millisekunder efter en skrivning innan den rapporterar att en transaktion har begått, för att garantera extern konsistens.

Utan TrueTime eller en liknande anläggning måste CockroachDB falla tillbaka till NTP, vilket ger övre gränser för klocksynkronisering mellan 100 millisekunder och 250 millisekunder. Med tanke på det större tidsfönstret väntar inte CockroachDB efter skrivningar. Istället väntar det ibland innan det läses, och omstartar i princip en transaktion om den läser ett värde med en tidsstämpel som är större än början på transaktionen, igen för att garantera konsistens.

När alla noder i ett CockroachDB-kluster har de små övre gränserna för klockförskjutningar som du kan få från GPS eller atomur, vilket är något som bara blir tillgängligt i stora offentliga moln, kan det vara vettigt att köra dem med --linearizable flaggan. Det får dem att vänta på den maximala klockförskjutningen innan de returnerar ett lyckat engagemang, precis som Spanner.

Hur CockroachDB fungerar

Varje CockroachDB-nod består av fem lager:

  • SQL, som översätter klient-SQL-frågor till nyckel-värde-operationer
  • Transaktion, vilket möjliggör atomförändringar i flera nyckel-värdeposter
  • Distribution, som presenterar replikerade nyckel-värdeområden som en enda enhet
  • Replikering, som konsekvent och synkront replikerar nyckelvärdesintervall över många noder och möjliggör konsekvent läsning via hyresavtal
  • Storage, som skriver och läser nyckel-värdedata på disk

SQL-lagret analyserar frågor mot en Yacc-fil och förvandlar dem till ett abstrakt syntaxträd. Från det abstrakta syntaxträdet genererar CockroachDB ett träd av plannoder som innehåller nyckel-värdekod. Plannoderna körs sedan och kommunicerar med transaktionsskiktet.

Transaktionsskiktet implementerar ACID-transaktionssemantik med tvåfasförpliktelser över hela klustret inklusive transaktioner över gränserna och tvärbord, och behandlar enskilda uttalanden som transaktioner (kallas även auto-commit-läge) Tvåfasförpliktelsen åstadkoms genom att bokföra transaktionsregister och skriva avsikter, utföra läsoperationer och behandla eventuella skrivavsättningar som transaktionskonflikter.

Distributionsskiktet tar emot förfrågningar från transaktionsskiktet på samma nod. Den identifierar sedan vilka noder som ska ta emot begäran och skickar begäran till rätt nods replikeringslager.

Replikeringslagret kopierar data mellan noder och säkerställer konsekvens mellan dessa kopior genom att implementera en Raft-konsensusalgoritm. Du kan styra replikeringsfaktorn på kluster, databas och tabellnivå med replikeringszoner. Konsensusalgoritmen används endast för skrivningar och kräver att ett antal repliker är överens om alla ändringar i ett intervall innan dessa ändringar görs.

Lagringslagret lagrar data som nyckel-värdepar på disken med RocksDB. CockroachDB är starkt beroende av multi-version concurrency control (MVCC) för att behandla samtidiga förfrågningar och garantera konsistens. Mycket av detta arbete görs genom att använda tidsstämplar för hybrid logisk klocka (HLC).

Liksom Spanner stöder CockroachDB tidsresor (aktiverade av MVCC). Dessa kan gå tillbaka så långt som din senaste databasavfallssamling, gjort som standard dagligen.

CockroachDB installation och användning

CockroachDB körs på Mac, Linux och Windows operativsystem, åtminstone för utveckling och test. Produktion Cockroach-databaser körs vanligtvis på virtuella Linux-datorer eller orkestrerade behållare, ofta värd på offentliga moln i flera datacenter. Windows-binärprogrammet för CockroachDB är fortfarande i en beta-fas och rekommenderas inte för produktion, och Apple tillverkar inte längre serverhårdvara.

Cockroach Labs

Som du kan se på skärmdumpen ovan finns det fyra alternativ för att installera CockroachDB på en Mac. Jag valde Homebrew som troligen den enklaste av de fyra.

Förresten, Cockroach Labs publicerar en varning på webbplatsen som säger att det är svårt att köra en statlig applikation som CockroachDB i Docker, inte rekommenderas för produktionsdistributioner och att använda ett orkestreringsverktyg som Kubernetes eller Docker Swarm för att köra ett kluster istället. Jag kommer att diskutera alternativ för containerorkestrering i nästa avsnitt.

Installation på en Mac är lika enkel brew install cockroachsom ovan. I mitt fall tog den automatiska uppdateringen av Homebrew mycket längre tid (tillräckligt med tid för att brygga te) än den faktiska CockroachDB-installationen, som bara tog några sekunder.

När du har installerat CockroachDB är det ganska enkelt att snurra upp ett lokalt kluster, även om det finns det extra steget att generera säkerhetscertifikat med cockroach certkommandot om du vill att klustret ska vara säkert. När du har kört ett kluster (använder cockroach startkommandot en gång för varje nod, med efterföljande noder inställda för att gå med i den första nodens kluster), kan du ansluta till webbadministrationssidan i vilken nod som helst med en webbläsare och använda den inbäddade cockroach sqlklienten för att skicka SQL frågor till vilken nod som helst. De flesta webbläsare kommer att klaga på webbplatser med CockroachDB-genererade certifikat, men du borde kunna klicka igenom den dystra varningen och fortsätta till webbplatsen.

De rekommenderade produktionsinställningarna för CockroachDB skiljer sig från standardvärdena som konfigurerades för utvecklings- och testinstanser. Du kan utvecklas i ett kluster med en nod om du vill. För produktion bör du ha minst tre noder, köra varje nod på en separat dator, virtuell dator eller container och ge varje instans extra cache och SQL-minne. Standardinställningarna är 128 MB vardera för cache och SQL-minne; de rekommenderade produktionsinställningarna är att ge 25 procent av RAM:

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

Ju fler noder du kör, desto bättre blir flexibiliteten. Ju större och snabbare noder, desto bättre prestanda. Om du vill ha noder med prestanda som är ungefär jämförbara med Google Cloud Spanner-noder, som levererar 2000 skrivningar per sekund och 10 000 läsningar per sekund, skulle du vilja ha något som GCE: s n1-highcpu-8-instanser, som har åtta processorer och 8 GB RAM , med lokala SSD-skivor (snarare än snurrande skivor).

Ju mer du distribuerar dina noder till olika datacenter, desto bättre kan du säkerställa immunitet mot fel på datacenternivå. Det tillkommer dock en kostnad: Retur latenstiden mellan datacenter kommer att ha en direkt effekt på din databas prestanda, med kluster över hela kontinenten som fungerar märkbart sämre än kluster där alla noder är geografiskt nära varandra.

Cockroach Labs tillhandahåller detaljerade instruktioner för distribution på AWS, Digital Ocean, GCE och Azure. De rekommenderade konfigurationerna använder belastningsutjämnare, antingen de inbyggda hanterade belastningsbalanseringstjänsterna eller öppen källkodsbelastningsutjämnare som HAProxy.

Orkestrering kan sänka driftkostnaderna för ett CockroachDB-kluster till nästan ingenting. Cockroach Labs dokumenterar hur man gör detta för produktion med Kubernetes och Docker Swarm. CockroachDB-CloudFormation-förvaret på GitHub visar hur man använder AWS CloudFormation och Kubernetes i en enda tillgänglighetszon för utveckling och test. Att anpassa detta för produktion skulle innebära att CloudFormation-mallen modifierades för att använda flera tillgänglighetszoner.

CockroachDB programmering och testning

CockroachDB stöder PostgreSQL-trådprotokollet, så du skriver din kod som om du programmerade mot Postgres eller åtminstone en delmängd Postgres. Den här sidan visar de testade drivrutinerna för olika programmeringsspråksbindningar, inklusive de mest populära serverspråken. Denna sida listar exempel på tio programmeringsspråk och fem ORM. Jag stötte inte på några stora överraskningar när jag läste igenom koden, även om jag upptäckte några troliga mindre buggar i listorna i dokumentationen. Du kan också köra din SQL med den interaktiva klienten som är inbyggd i den cockroachkörbara filen.

Även om det finns en repo som är dedikerad till CockroachDB-belastningsgeneratorer och en annan för prestandatest, är benchmarking av CockroachDB-kluster inte lätt, speciellt om du försöker jämföra CockroachDB med andra databaser på ett meningsfullt sätt. En fråga är att nätverket bland noder kan vara det hastighetsbegränsande steget i CockroachDB-kluster.

Ett annat faktum att ta hänsyn till är att de flesta konventionella SQL-databaser inte körs i SERIALISERBART isoleringsläge som standard; istället använder de ett mindre strikt läge med bättre prestanda. CockroachDB använder standardiserat isoleringsläge. Dessutom skulle det vara lite orättvist att testa CockroachDB: s SQL-kopplingsprestanda, som fortfarande pågår, med TPC-C-sviten.

Och ändå kan du enkelt se den operativa kraften hos CockroachDB. Till exempel måste många databaser stoppas och startas om för att skala upp dem. Att lägga till noder under belastning i CockroachDB är en lek, speciellt om du använder ett orkestreringsverktyg. Exempelvis visar skärmdumpen ovan kommandona för att ändra och visa noder i ett Kubernetes-kluster, och skärmdumpen nedan visar det övervakade klustret när noderna läggs till. Ett lastgenererande verktyg kördes kontinuerligt under hela processen.

En ännu mer imponerande demonstration visar automatisk migrering över molnet i ett CockroachDB-kluster. Det kräver verkligen video för att göra det rättvisa; videon är värd i det länkade blogginlägget.

CockroachDB SQL 

SQL i CockroachDB är mer eller mindre standard, till skillnad från SQL i Cloud Spanner, som använder icke-standard syntax för datamanipulation. CockroachDB SQL saknar dock fortfarande många funktioner.

Till exempel saknar V1.1 JSON-stöd, vilket är planerat för V1.2. Det saknas också XML-parsing, vilket inte finns på färdplanen. Den saknar kaskader på radnivå, planerad för V1.2, och saknar markörer och utlösare, som inte finns på färdplanen. Geospatiala index är "potentiella" tillägg som kan göra det till färdplanen i framtiden.

Framför allt var den ursprungliga CockroachDB-implementeringen av SQL-anslutningar 2016 medvetet förenklad och uppvisade kvadratisk skalning, vilket gjorde den värdelös för att fråga stora datamängder. Versionen i V1.0, gjord av en samarbetsstudent, implementerade hash-sammanfogningar, vilket gör att många anslutningsoperationer skalas linjärt; som fick CockroachDB till nivå med SQLite. Någon gång under 2018, med tanke på en nyligen genomförd finansieringsrunda, skulle CockroachDB ha anslutit till prestanda som skalas mer som PostgreSQL-anslutningar, liksom bearbetning av SQL-anslutning fördelat över klustret.