Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni

Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni

Incontriamo regolarmente il database Apache Cassandra e la necessità di gestirlo all'interno di un'infrastruttura basata su Kubernetes. In questo materiale condivideremo la nostra visione dei passaggi necessari, dei criteri e delle soluzioni esistenti (inclusa una panoramica degli operatori) per la migrazione di Cassandra su K8.

“Chi può governare una donna può anche governare lo Stato”

Chi è Cassandra? Si tratta di un sistema di storage distribuito progettato per gestire grandi volumi di dati garantendo allo stesso tempo un'elevata disponibilità senza un singolo punto di guasto. Il progetto non ha certo bisogno di una lunga introduzione, quindi fornirò solo le caratteristiche principali di Cassandra che saranno rilevanti nel contesto di un articolo specifico:

  • Cassandra è scritto in Java.
  • La topologia Cassandra comprende diversi livelli:
    • Nodo: un'istanza Cassandra distribuita;
    • Rack è un gruppo di istanze Cassandra, accomunate da alcune caratteristiche, situate nello stesso data center;
    • Datacenter: una raccolta di tutti i gruppi di istanze Cassandra situate in un data center;
    • Il cluster è una raccolta di tutti i data center.
  • Cassandra utilizza un indirizzo IP per identificare un nodo.
  • Per velocizzare le operazioni di scrittura e lettura, Cassandra memorizza alcuni dati nella RAM.

Passiamo ora all'effettivo potenziale passaggio a Kubernetes.

Check-list per il trasferimento

Parlando della migrazione di Cassandra su Kubernetes, speriamo che con lo spostamento diventi più conveniente da gestire. Cosa sarà richiesto per questo, cosa aiuterà in questo?

1. Archiviazione dei dati

Come già chiarito, Cassanda memorizza parte dei dati nella RAM-in Memorabile. Ma c'è un'altra parte dei dati che viene salvata su disco: nel modulo SSTable. A questi dati viene aggiunta un'entità Registro dei commit — registrazioni di tutte le transazioni, che vengono anche salvate su disco.

Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni
Scrivi il diagramma delle transazioni in Cassandra

In Kubernetes possiamo utilizzare PersistentVolume per archiviare i dati. Grazie a meccanismi collaudati, lavorare con i dati in Kubernetes diventa ogni anno più semplice.

Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni
Assegneremo il nostro PersistentVolume a ciascun pod Cassandra

È importante notare che Cassandra stessa implica la replica dei dati, offrendo meccanismi integrati per questo. Pertanto, se stai creando un cluster Cassandra da un numero elevato di nodi, non è necessario utilizzare sistemi distribuiti come Ceph o GlusterFS per l'archiviazione dei dati. In questo caso, sarebbe logico archiviare i dati sul disco host utilizzando dischi persistenti locali o montaggio hostPath.

Un'altra domanda è se desideri creare un ambiente separato per gli sviluppatori per ciascun ramo di funzionalità. In questo caso, l'approccio corretto sarebbe quello di creare un nodo Cassandra e archiviare i dati in uno spazio di archiviazione distribuito, ovvero i menzionati Ceph e GlusterFS saranno le tue opzioni. Quindi lo sviluppatore sarà sicuro di non perdere i dati dei test anche se uno dei nodi del cluster Kuberntes viene perso.

2. Monitoraggio

La scelta praticamente incontestata per l’implementazione del monitoraggio in Kubernetes è Prometheus (ne abbiamo parlato approfonditamente in relativo rapporto). Come se la cava Cassandra con gli esportatori di metriche per Prometheus? E cosa è ancora più importante, con dashboard corrispondenti per Grafana?

Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni
Un esempio della comparsa di grafici in Grafana per Cassandra

Ci sono solo due esportatori: jmx_exporter и cassandra_exporter.

Abbiamo scelto per noi il primo perché:

  1. JMX Exporter sta crescendo e sviluppandosi, mentre Cassandra Exporter non è riuscita a ottenere abbastanza sostegno dalla comunità. Cassandra Exporter continua a non supportare la maggior parte delle versioni di Cassandra.
  2. Puoi eseguirlo come javaagent aggiungendo un flag -javaagent:<plugin-dir-name>/cassandra-exporter.jar=--listen=:9180.
  3. Ce n'è uno per lui cruscotto adeguato, che è incompatibile con Cassandra Exporter.

3. Selezione delle primitive Kubernetes

Secondo la struttura sopra del cluster Cassandra, proviamo a tradurre tutto ciò che è descritto nella terminologia Kubernetes:

  • Nodo Cassandra → Pod
  • Rack Cassandra → StatefulSet
  • Cassandra Datacenter → pool da StatefulSets
  • Ammasso Cassandra → ???

Si scopre che manca qualche entità aggiuntiva per gestire l'intero cluster Cassandra contemporaneamente. Ma se qualcosa non esiste, possiamo crearlo! Kubernetes dispone di un meccanismo per definire le proprie risorse a questo scopo: Definizioni di risorse personalizzate.

Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni
Dichiarare risorse aggiuntive per log e avvisi

Ma Custom Resource in sé non significa nulla: dopo tutto, richiede controllore. Potrebbe essere necessario cercare aiuto Operatore Kubernetes...

4. Identificazione dei baccelli

Nel paragrafo precedente abbiamo concordato che un nodo Cassandra equivarrà a un pod in Kubernetes. Ma gli indirizzi IP dei pod saranno ogni volta diversi. E l'identificazione di un nodo in Cassandra si basa sull'indirizzo IP... Risulta che dopo ogni rimozione di un pod, il cluster Cassandra aggiungerà un nuovo nodo.

C'è una via d'uscita, e non solo una:

  1. Possiamo conservare i record in base agli identificatori host (UUID che identificano in modo univoco le istanze di Cassandra) o in base agli indirizzi IP e archiviarli tutti in alcune strutture/tabelle. Il metodo presenta due principali svantaggi:
    • Il rischio che si verifichi una condizione di competizione se due nodi cadono contemporaneamente. Dopo l'aumento, i nodi Cassandra richiederanno contemporaneamente un indirizzo IP dalla tabella e competeranno per la stessa risorsa.
    • Se un nodo Cassandra ha perso i suoi dati, non saremo più in grado di identificarlo.
  2. La seconda soluzione sembra un piccolo trucco, ma comunque: possiamo creare un servizio con ClusterIP per ogni nodo Cassandra. Problemi con questa implementazione:
    • Se ci sono molti nodi in un cluster Cassandra, dovremo creare molti servizi.
    • La funzionalità ClusterIP è implementata tramite iptables. Questo può diventare un problema se il cluster Cassandra ha molti (1000... o anche 100?) nodi. Sebbene bilanciamento basato su IPVS può risolvere questo problema.
  3. La terza soluzione è utilizzare una rete di nodi per i nodi Cassandra invece di una rete dedicata di pod abilitando l'impostazione hostNetwork: true. Questo metodo impone alcune limitazioni:
    • Per sostituire le unità. È necessario che il nuovo nodo abbia lo stesso indirizzo IP del precedente (nei cloud come AWS, GCP questo è quasi impossibile da fare);
    • Utilizzando una rete di nodi cluster, iniziamo a competere per le risorse di rete. Pertanto, posizionare più di un pod con Cassandra su un nodo del cluster sarà problematico.

5. Backup

Vogliamo salvare una versione completa dei dati di un singolo nodo Cassandra in base a una pianificazione. Kubernetes fornisce una comoda funzionalità utilizzando CronJob, ma qui Cassandra stessa ci mette i bastoni tra le ruote.

Lascia che ti ricordi che Cassandra memorizza alcuni dati in memoria. Per eseguire un backup completo, sono necessari i dati dalla memoria (Memtables) sposta sul disco (SSTables). A questo punto il nodo Cassandra smette di accettare connessioni, spegnendosi completamente dal cluster.

Successivamente, il backup viene rimosso (istantanea) e lo schema viene salvato (spazio chiave). E poi si scopre che solo un backup non ci dà nulla: dobbiamo salvare gli identificatori di dati di cui era responsabile il nodo Cassandra: questi sono token speciali.

Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni
Distribuzione di token per identificare di quali dati sono responsabili i nodi Cassandra

È possibile trovare uno script di esempio per eseguire un backup di Cassandra da Google in Kubernetes all'indirizzo questo link. L'unico punto di cui lo script non tiene conto è il ripristino dei dati sul nodo prima di acquisire lo snapshot. Cioè, il backup viene eseguito non per lo stato corrente, ma per uno stato leggermente precedente. Ma questo aiuta a non mettere fuori servizio il nodo, il che sembra molto logico.

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}"

Un esempio di script bash per eseguire un backup da un nodo Cassandra

Soluzioni pronte per Cassandra in Kubernetes

Cosa viene attualmente utilizzato per distribuire Cassandra in Kubernetes e quale di questi si adatta meglio ai requisiti specificati?

1. Soluzioni basate su grafici StatefulSet o Helm

L'utilizzo delle funzioni StatefulSets di base per eseguire un cluster Cassandra è una buona opzione. Utilizzando il grafico Helm e i modelli Go, puoi fornire all'utente un'interfaccia flessibile per la distribuzione di Cassandra.

Di solito funziona bene... finché non accade qualcosa di inaspettato, come un guasto del nodo. Gli strumenti Kubernetes standard semplicemente non possono tenere conto di tutte le funzionalità sopra descritte. Inoltre, questo approccio è molto limitato in quanto può essere esteso per usi più complessi: sostituzione dei nodi, backup, ripristino, monitoraggio, ecc.

rappresentanti:

Entrambi i grafici sono ugualmente buoni, ma sono soggetti ai problemi sopra descritti.

2. Soluzioni basate su Kubernetes Operator

Tali opzioni sono più interessanti perché offrono ampie opportunità per la gestione del cluster. Per progettare un operatore Cassandra, come qualsiasi altro database, un buon modello è Sidecar <-> Controller <-> CRD:

Migrazione da Cassandra a Kubernetes: caratteristiche e soluzioni
Schema di gestione dei nodi in un operatore Cassandra ben progettato

Diamo un'occhiata agli operatori esistenti.

1. Operatore Cassandra di instaclustr

  • GitHub
  • Prontezza: alfa
  • Licenza: Apache 2.0
  • Implementato in: Java

Questo è davvero un progetto molto promettente e in fase di sviluppo attivo da parte di un'azienda che offre implementazioni gestite di Cassandra. Come descritto sopra, utilizza un contenitore sidecar che accetta comandi tramite HTTP. Scritto in Java, a volte manca le funzionalità più avanzate della libreria client-go. Inoltre, l'operatore non supporta rack diversi per un Datacenter.

Ma l'operatore ha vantaggi come il supporto per il monitoraggio, la gestione dei cluster di alto livello tramite CRD e persino la documentazione per l'esecuzione dei backup.

2. Navigatore da Jetstack

  • GitHub
  • Prontezza: alfa
  • Licenza: Apache 2.0
  • Implementato in: Golang

Una dichiarazione progettata per distribuire DB-as-a-Service. Attualmente supporta due database: Elasticsearch e Cassandra. Ha soluzioni interessanti come il controllo dell'accesso al database tramite RBAC (per questo ha il proprio navigatore-apiserver separato). Un progetto interessante che varrebbe la pena approfondire, ma l'ultimo impegno è stato effettuato un anno e mezzo fa, il che ne riduce chiaramente le potenzialità.

3. Operatore Cassandra di vgkowski

  • GitHub
  • Prontezza: alfa
  • Licenza: Apache 2.0
  • Implementato in: Golang

Non l’hanno considerato “sul serio”, dal momento che l’ultimo commit del repository è avvenuto più di un anno fa. Lo sviluppo degli operatori viene abbandonato: l'ultima versione di Kubernetes segnalata come supportata è la 1.9.

4. Operatore Cassandra di Rook

  • GitHub
  • Prontezza: alfa
  • Licenza: Apache 2.0
  • Implementato in: Golang

Un operatore il cui sviluppo non procede così velocemente come vorremmo. Ha una struttura CRD ben congegnata per la gestione dei cluster, risolve il problema dell'identificazione dei nodi utilizzando Service with ClusterIP (lo stesso "hack")... ma per ora è tutto. Al momento non è disponibile alcun monitoraggio o backup immediato (a proposito, siamo per il monitoraggio l'abbiamo preso noi stessi). Un punto interessante è che puoi anche distribuire ScyllaDB utilizzando questo operatore.

NB: Abbiamo utilizzato questo operatore con piccole modifiche in uno dei nostri progetti. Non sono stati notati problemi nel lavoro dell’operatore durante l’intero periodo di funzionamento (~4 mesi di funzionamento).

5. CassKop di Orange

  • GitHub
  • Prontezza: alfa
  • Licenza: Apache 2.0
  • Implementato in: Golang

L'operatore più giovane della lista: il primo commit è stato effettuato il 23 maggio 2019. Già ora ha nel suo arsenale un gran numero di funzionalità dal nostro elenco, maggiori dettagli possono essere trovati nel repository del progetto. L'operatore è costruito sulla base del popolare operator-sdk. Supporta il monitoraggio immediato. La differenza principale rispetto agli altri operatori è l'utilizzo Plug-in CassKop, implementato in Python e utilizzato per la comunicazione tra i nodi Cassandra.

risultati

Il numero di approcci e possibili opzioni per il porting di Cassandra su Kubernetes parla da solo: l'argomento è molto richiesto.

In questa fase, puoi provare qualsiasi delle soluzioni precedenti a tuo rischio e pericolo: nessuno degli sviluppatori garantisce il funzionamento al 100% della propria soluzione in un ambiente di produzione. Ma già molti prodotti sembrano promettenti da provare a utilizzare nei banchi di sviluppo.

Penso che in futuro questa donna sulla nave tornerà utile!

PS

Leggi anche sul nostro blog:

Fonte: habr.com

Aggiungi un commento