Migrering av Cassandra till Kubernetes: funktioner och lösningar

Migrering av Cassandra till Kubernetes: funktioner och lösningar

Vi stöter regelbundet på Apache Cassandra-databasen och behovet av att driva den inom en Kubernetes-baserad infrastruktur. I detta material kommer vi att dela vår vision om nödvändiga steg, kriterier och befintliga lösningar (inklusive en översikt över operatörer) för att migrera Cassandra till K8s.

"Den som kan styra en kvinna kan också styra staten"

Vem är Cassandra? Det är ett distribuerat lagringssystem designat för att hantera stora datamängder samtidigt som det säkerställer hög tillgänglighet utan en enda punkt av fel. Projektet behöver knappast en lång introduktion, så jag kommer bara att ge huvuddragen i Cassandra som kommer att vara relevanta i samband med en specifik artikel:

  • Cassandra är skriven på Java.
  • Cassandra-topologin inkluderar flera nivåer:
    • Node - en utplacerad Cassandra-instans;
    • Rack är en grupp av Cassandra-instanser, förenade av någon egenskap, belägna i samma datacenter;
    • Datacenter - en samling av alla grupper av Cassandra-instanser som finns i ett datacenter;
    • Cluster är en samling av alla datacenter.
  • Cassandra använder en IP-adress för att identifiera en nod.
  • För att påskynda skriv- och läsoperationerna lagrar Cassandra en del av datan i RAM.

Nu - till den faktiska potentiella flytten till Kubernetes.

Checklista för överföring

På tal om migreringen av Cassandra till Kubernetes, hoppas vi att det med flytten blir mer bekvämt att hantera. Vad kommer att krävas för detta, vad hjälper till med detta?

1. Datalagring

Som redan har klarlagts lagrar Cassanda en del av datan i RAM - in Minnesbar. Men det finns en annan del av data som sparas på disk - i formuläret SSTable. En enhet läggs till denna data Commit Log — register över alla transaktioner, som också sparas på disk.

Migrering av Cassandra till Kubernetes: funktioner och lösningar
Skriv transaktionsdiagram i Cassandra

I Kubernetes kan vi använda PersistentVolume för att lagra data. Tack vare beprövade mekanismer blir arbetet med data i Kubernetes enklare för varje år.

Migrering av Cassandra till Kubernetes: funktioner och lösningar
Vi kommer att allokera vår egen PersistentVolume till varje Cassandra pod

Det är viktigt att notera att Cassandra själv innebär datareplikering och erbjuder inbyggda mekanismer för detta. Därför, om du bygger ett Cassandra-kluster från ett stort antal noder, så finns det inget behov av att använda distribuerade system som Ceph eller GlusterFS för datalagring. I det här fallet skulle det vara logiskt att lagra data på värddisken med hjälp av lokala beständiga diskar eller montering hostPath.

En annan fråga är om du vill skapa en separat miljö för utvecklare för varje funktionsgren. I det här fallet skulle det korrekta tillvägagångssättet vara att höja en Cassandra-nod och lagra data i en distribuerad lagring, dvs. de nämnda Ceph och GlusterFS kommer att vara dina alternativ. Då kommer utvecklaren att vara säker på att han inte kommer att förlora testdata även om en av Kuberntes-klusternoderna går förlorad.

2. Övervakning

Det praktiskt taget obestridda valet för att implementera övervakning i Kubernetes är Prometheus (vi pratade om detta i detalj i relaterad rapport). Hur går det för Cassandra med måttexportörer för Prometheus? Och vad är ännu viktigare, med matchande instrumentpaneler för Grafana?

Migrering av Cassandra till Kubernetes: funktioner och lösningar
Ett exempel på utseendet på grafer i Grafana för Cassandra

Det finns bara två exportörer: jmx_exporter и cassandra_exporter.

Vi valde den första för oss själva eftersom:

  1. JMX Exporter växer och utvecklas, medan Cassandra Exporter inte har kunnat få tillräckligt med gemenskapsstöd. Cassandra Exporter stöder fortfarande inte de flesta versioner av Cassandra.
  2. Du kan köra den som en javaagent genom att lägga till en flagga -javaagent:<plugin-dir-name>/cassandra-exporter.jar=--listen=:9180.
  3. Det finns en för honom adekvat instrumentpanel, vilket är inkompatibelt med Cassandra Exporter.

3. Välja Kubernetes primitiver

Enligt ovanstående struktur för Cassandra-klustret, låt oss försöka översätta allt som beskrivs där till Kubernetes terminologi:

  • Cassandra Node → Pod
  • Cassandra Rack → StatefulSet
  • Cassandra Datacenter → pool från StatefulSets
  • Cassandra Cluster → ???

Det visar sig att någon ytterligare enhet saknas för att hantera hela Cassandra-klustret på en gång. Men om något inte finns kan vi skapa det! Kubernetes har en mekanism för att definiera sina egna resurser för detta ändamål - Anpassade resursdefinitioner.

Migrering av Cassandra till Kubernetes: funktioner och lösningar
Deklarerar ytterligare resurser för loggar och varningar

Men Custom Resource i sig betyder ingenting: det kräver trots allt regulator. Du kan behöva söka hjälp Kubernetes operatör.

4. Identifiering av baljor

I stycket ovan kom vi överens om att en Cassandra-nod är lika med en pod i Kubernetes. Men IP-adresserna för poddarna kommer att vara olika varje gång. Och identifieringen av en nod i Cassandra baseras på IP-adressen... Det visar sig att efter varje borttagning av en pod kommer Cassandra-klustret att lägga till en ny nod.

Det finns en väg ut och inte bara en:

  1. Vi kan föra register efter värdidentifierare (UUID som unikt identifierar Cassandra-instanser) eller efter IP-adresser och lagra allt i vissa strukturer/tabeller. Metoden har två huvudsakliga nackdelar:
    • Risken för att ett rastillstånd uppstår om två noder faller samtidigt. Efter uppgången kommer Cassandra-noder samtidigt att begära en IP-adress från tabellen och tävla om samma resurs.
    • Om en Cassandra-nod har förlorat sin data kommer vi inte längre att kunna identifiera den.
  2. Den andra lösningen verkar vara ett litet hack, men inte desto mindre: vi kan skapa en tjänst med ClusterIP för varje Cassandra-nod. Problem med denna implementering:
    • Om det finns många noder i ett Cassandra-kluster måste vi skapa många tjänster.
    • ClusterIP-funktionen implementeras via iptables. Detta kan bli ett problem om Cassandra-klustret har många (1000... eller till och med 100?) noder. Fastän balansering baserad på IPVS kan lösa detta problem.
  3. Den tredje lösningen är att använda ett nätverk av noder för Cassandra-noder istället för ett dedikerat nätverk av pods genom att aktivera inställningen hostNetwork: true. Denna metod inför vissa begränsningar:
    • För att byta ut enheter. Det är nödvändigt att den nya noden måste ha samma IP-adress som den tidigare (i moln som AWS, GCP är detta nästan omöjligt att göra);
    • Med hjälp av ett nätverk av klusternoder börjar vi konkurrera om nätverksresurser. Därför kommer det att vara problematiskt att placera mer än en pod med Cassandra på en klusternod.

5. Säkerhetskopieringar

Vi vill spara en fullständig version av en enda Cassandra-nods data enligt ett schema. Kubernetes tillhandahåller en bekväm funktion med hjälp av Cron jobb, men här sätter Cassandra själv en eker i våra hjul.

Låt mig påminna dig om att Cassandra lagrar en del av datan i minnet. För att göra en fullständig säkerhetskopia behöver du data från minnet (Memtables) flytta till disk (SSTables). Vid denna tidpunkt slutar Cassandra-noden att acceptera anslutningar och stängs helt av från klustret.

Efter detta tas säkerhetskopian bort (ögonblicksbild) och schemat sparas (tangentutrymme). Och sedan visar det sig att bara en säkerhetskopia inte ger oss någonting: vi måste spara dataidentifierarna som Cassandra-noden var ansvarig för - dessa är speciella tokens.

Migrering av Cassandra till Kubernetes: funktioner och lösningar
Distribution av tokens för att identifiera vilken data Cassandra noder ansvarar för

Ett exempelskript för att ta en Cassandra-säkerhetskopia från Google i Kubernetes finns på denna länk. Den enda punkt som skriptet inte tar hänsyn till är att återställa data till noden innan ögonblicksbilden tas. Det vill säga, säkerhetskopieringen utförs inte för det aktuella tillståndet, utan för ett tillstånd lite tidigare. Men detta hjälper till att inte ta noden ur drift, vilket verkar väldigt logiskt.

set -eu

if [[ -z "$1" ]]; then
  info "Please provide a keyspace"
  exit 1
fi

KEYSPACE="$1"

result=$(nodetool snapshot "${KEYSPACE}")

if [[ $? -ne 0 ]]; then
  echo "Error while making snapshot"
  exit 1
fi

timestamp=$(echo "$result" | awk '/Snapshot directory: / { print $3 }')

mkdir -p /tmp/backup

for path in $(find "/var/lib/cassandra/data/${KEYSPACE}" -name $timestamp); do
  table=$(echo "${path}" | awk -F "[/-]" '{print $7}')
  mkdir /tmp/backup/$table
  mv $path /tmp/backup/$table
done


tar -zcf /tmp/backup.tar.gz -C /tmp/backup .

nodetool clearsnapshot "${KEYSPACE}"

Ett exempel på ett bash-skript för att ta en säkerhetskopia från en Cassandra-nod

Färdiga lösningar för Cassandra i Kubernetes

Vad används för närvarande för att distribuera Cassandra i Kubernetes och vilken av dessa passar bäst de givna kraven?

1. Lösningar baserade på StatefulSet- eller Helm-diagram

Att använda de grundläggande StatefulSets-funktionerna för att köra ett Cassandra-kluster är ett bra alternativ. Med hjälp av Helm-diagrammet och Go-mallarna kan du ge användaren ett flexibelt gränssnitt för att distribuera Cassandra.

Detta fungerar vanligtvis bra... tills något oväntat händer, till exempel ett nodfel. Standard Kubernetes-verktyg kan helt enkelt inte ta hänsyn till alla funktioner som beskrivs ovan. Dessutom är detta tillvägagångssätt mycket begränsat i hur mycket det kan utökas för mer komplexa användningsområden: nodbyte, säkerhetskopiering, återställning, övervakning, etc.

Representanter:

Båda diagrammen är lika bra, men är föremål för de problem som beskrivs ovan.

2. Lösningar baserade på Kubernetes Operator

Sådana alternativ är mer intressanta eftersom de ger stora möjligheter att hantera klustret. För att designa en Cassandra-operatör, som vilken annan databas som helst, ser ett bra mönster ut som Sidecar <-> Controller <-> CRD:

Migrering av Cassandra till Kubernetes: funktioner och lösningar
Nodhanteringsschema i en väldesignad Cassandra-operatör

Låt oss titta på befintliga operatörer.

1. Cassandra-operatör från instaclustr

  • GitHub
  • Beredskap: Alfa
  • Licens: Apache 2.0
  • Implementerad i: Java

Detta är verkligen ett mycket lovande och aktivt utvecklande projekt från ett företag som erbjuder hanterade Cassandra-distributioner. Den, som beskrivits ovan, använder en sidovagnsbehållare som accepterar kommandon via HTTP. Skrivet i Java, saknar det ibland den mer avancerade funktionaliteten i client-go-biblioteket. Operatören stöder inte heller olika rack för ett datacenter.

Men operatören har sådana fördelar som stöd för övervakning, klusterhantering på hög nivå med CRD och till och med dokumentation för säkerhetskopiering.

2. Navigator från Jetstack

  • GitHub
  • Beredskap: Alfa
  • Licens: Apache 2.0
  • Implementerad i: Golang

Ett uttalande utformat för att distribuera DB-as-a-Service. Stöder för närvarande två databaser: Elasticsearch och Cassandra. Den har så intressanta lösningar som databasåtkomstkontroll via RBAC (för detta har den sin egen separata navigator-apiserver). Ett intressant projekt som vore värt att titta närmare på, men den senaste commit gjordes för ett och ett halvt år sedan, vilket klart minskar dess potential.

3. Cassandra-operatör av vgkowski

  • GitHub
  • Beredskap: Alfa
  • Licens: Apache 2.0
  • Implementerad i: Golang

De ansåg inte att det var "allvarligt", eftersom den senaste förbindelsen till förvaret var för mer än ett år sedan. Operatörsutveckling har övergetts: den senaste versionen av Kubernetes som rapporteras som stödd är 1.9.

4. Cassandra-operatör av Rook

  • GitHub
  • Beredskap: Alfa
  • Licens: Apache 2.0
  • Implementerad i: Golang

En operatör vars utveckling inte går så snabbt som vi skulle önska. Den har en genomtänkt CRD-struktur för klusterhantering, löser problemet med att identifiera noder som använder Service med ClusterIP (samma "hack")... men det var allt för nu. Det finns för närvarande ingen övervakning eller säkerhetskopior ur lådan (förresten, vi är för övervakning tog det själva). En intressant punkt är att du också kan distribuera ScyllaDB med den här operatören.

OBS: Vi använde denna operatör med mindre modifieringar i ett av våra projekt. Inga problem märktes i operatörens arbete under hela driftperioden (~4 månaders drift).

5. CassKop från Orange

  • GitHub
  • Beredskap: Alfa
  • Licens: Apache 2.0
  • Implementerad i: Golang

Den yngsta operatören på listan: det första åtagandet gjordes den 23 maj 2019. Redan nu har den i sin arsenal ett stort antal funktioner från vår lista, mer detaljer om vilka finns i projektförrådet. Operatören är byggd på basis av den populära operator-sdk. Stöder övervakning direkt från förpackningen. Den största skillnaden från andra operatörer är användningen CassKop plugin, implementerad i Python och används för kommunikation mellan Cassandra-noder.

Resultat

Antalet tillvägagångssätt och möjliga alternativ för att porta Cassandra till Kubernetes talar för sig själv: ämnet är efterfrågat.

I detta skede kan du prova något av ovanstående på egen risk och risk: ingen av utvecklarna garanterar 100 % drift av sin lösning i en produktionsmiljö. Men redan nu ser många produkter lovande ut att försöka använda i utvecklingsbänkar.

Jag tror att den här kvinnan på fartyget kommer att komma väl till pass i framtiden!

PS

Läs även på vår blogg:

Källa: will.com

Lägg en kommentar