Migrazione di Cassandra in Kubernetes: caratteristiche e soluzioni

Migrazione di Cassandra in Kubernetes: caratteristiche e soluzioni

Con il database Apache Cassandra e la necessità di gestirlo all'interno di un'infrastruttura basata su Kubernetes, ci confrontiamo regolarmente. In questo articolo condivideremo la nostra visione dei passi necessari, dei criteri e delle soluzioni esistenti (inclusa una panoramica degli operatori) per la migrazione di Cassandra in K8s.

«Chi può gestire una donna, può gestire anche uno stato»

Chi è Cassandra? È un sistema distribuito di archiviazione, progettato per gestire grandi volumi di dati, garantendo al contempo alta disponibilità senza un singolo punto di guasto. Il progetto non ha bisogno di lunghe presentazioni, quindi menzionerò solo le caratteristiche principali di Cassandra che saranno rilevanti per questo articolo:

  • Cassandra è scritta in Java.
  • La topologia di Cassandra include diversi livelli:
    • Node — un'istanza distribuita di Cassandra;
    • Rack — un gruppo di istanze di Cassandra, unite da qualche criterio, situate nello stesso data center;
    • Datacenter — l'insieme di tutti i gruppi di istanze di Cassandra che si trovano in un singolo data center;
    • Cluster — l'insieme di tutti i data center.
  • Per identificare un nodo, Cassandra utilizza un indirizzo IP.
  • Per velocizzare le operazioni di scrittura e lettura, parte dei dati di Cassandra viene memorizzata in memoria volatile.

Ora passiamo al potenziale trasferimento in Kubernetes.

Checklist per il trasferimento

Parlando della migrazione di Cassandra a Kubernetes, speriamo che trasferirei la gestione diventi più semplice. Cosa serve per questo e cosa può aiutare?

1. Storage per i dati

Come già indicato, parte dei dati di Cassandra viene memorizzata in memoria volatile — in Memtable. Ma c'è anche un'altra parte dei dati che viene salvata su disco, sotto forma di SSTable. A questi dati si aggiunge l'entità Commit Log — registrazioni di tutte le transazioni, che vengono anch'esse salvate su disco.

Migrazione di Cassandra in Kubernetes: caratteristiche e soluzioni
Schema delle transazioni di scrittura in Cassandra

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

Migrazione di Cassandra in Kubernetes: caratteristiche e soluzioni
Ad ogni pod di Cassandra assegneremo il proprio PersistentVolume.

È importante notare che Cassandra implica già la replica dei dati, fornendo meccanismi integrati per questo. Pertanto, se stai costruendo un cluster Cassandra con un gran numero di nodi, non è necessario utilizzare sistemi distribuiti come Ceph o GlusterFS per l'archiviazione dei dati. In questo caso, è logico memorizzare i dati sul disco del nodo tramite dischi persistenti locali o montaggio hostPath.

Un'altra questione è se desideri creare un ambiente separato per gli sviluppatori per ogni ramo della feature. In tal caso, l'approccio corretto sarebbe avviare un nodo Cassandra e memorizzare i dati in uno storage distribuito, quindi Ceph e GlusterFS diventerebbero una tua opzione. In questo modo, lo sviluppatore sarà certo di non perdere i dati di test anche in caso di perdita di uno dei nodi del cluster Kubernetes.

2. Monitoraggio

Una scelta praticamente senza alternative per implementare il monitoraggio in Kubernetes è Prometheus (di cui abbiamo parlato in dettaglio nel relativo report). Come se la cava Cassandra con gli exporter di metriche per Prometheus? E, cosa forse ancora più importante, con i dashboard adeguati per Grafana?

Migrazione di Cassandra in Kubernetes: caratteristiche e soluzioni
Esempio dell'aspetto dei grafici in Grafana per Cassandra

Ci sono solo due esportatori: jmx_exporter e cassandra_exporter.

Abbiamo scelto il primo perché:

  1. JMX Exporter è in crescita e si sta sviluppando, mentre Cassandra Exporter non ha ricevuto il giusto supporto dalla comunità. Cassandra Exporter non supporta ancora la maggior parte delle versioni di Cassandra.
  2. Può essere avviato come javaagent aggiungendo il flag -javaagent:/cassandra-exporter.jar=--listen=:9180.
  3. Per esso c'è un dashboard adeguato, che non è compatibile con Cassandra Exporter.

3. Scelta dei primitivi Kubernetes

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

  • Cassandra Node → Pod
  • Cassandra Rack → StatefulSet
  • Cassandra Datacenter → un pool di StatefulSet
  • Cassandra Cluster → ???

Sembra che manchi qualche entità aggiuntiva per gestire l'intero cluster Cassandra contemporaneamente. Ma se qualcosa manca, possiamo crearlo! In Kubernetes, esiste un meccanismo per definire risorse personalizzate — Custom Resource Definitions.

Migrazione di Cassandra in Kubernetes: caratteristiche e soluzioni
Dichiarazione di risorse aggiuntive per log e notifiche

Ma una Custom Resource di per sé non significa nulla: ha bisogno di controllore. Potrebbe essere necessario ricorrere all’aiuto di Kubernetes-operator

4. Identificazione dei pod

Nel punto precedente abbiamo concordato che un nodo Cassandra corrisponde a un pod in Kubernetes. Tuttavia, gli indirizzi IP dei pod saranno sempre diversi. L'identificazione del nodo in Cassandra avviene proprio sulla base dell'indirizzo IP… Quindi, dopo ogni eliminazione di un pod, il cluster Cassandra aggiungerà un nuovo nodo.

Ci sono soluzioni, e anche più di una:

  1. Possiamo tenere traccia attraverso identificatori univoci dei dispositivi (UUID) che identificano in modo univoco le istanze di Cassandra, oppure tramite indirizzi IP, memorizzando tutto in strutture/ Tabelle. Il metodo presenta due principali svantaggi:
    • Rischio di condizione di competizione in caso di guasto di due nodi contemporaneamente. Dopo il ripristino, i nodi Cassandra richiederanno simultaneamente un indirizzo IP dalla tabella, concorrendo per la stessa risorsa.
    • Se un nodo Cassandra perde i propri dati, non saremo più in grado di identificarlo.
  2. La seconda soluzione sembra un piccolo hack, ma comunque: possiamo creare un servizio con ClusterIP per ogni nodo Cassandra. I problemi di questa implementazione:
    • Se nel cluster Cassandra ci sono molti nodi, dovremo creare un numero molto elevato di servizi.
    • La possibilità di ClusterIP è realizzata tramite iptables. Questo può diventare un problema se nel cluster Cassandra ci sono molti (1000… o anche 100?) nodi. Anche se il bilanciamento basato su IPVS può risolvere questo problema.
  3. La terza soluzione è utilizzare la rete dei nodi per i nodi Cassandra invece di una rete dedicata ai pod attivando l'impostazione hostNetwork: true. Questo metodo comporta alcune limitazioni:
    • Sostituzione dei nodi. È necessario che un nuovo nodo abbia necessariamente lo stesso indirizzo IP del precedente (nelle nuvole come AWS, GCP, questo è praticamente impossibile);
    • Utilizzando la rete dei nodi del cluster, iniziamo a competere per le risorse di rete. Di conseguenza, posizionare più di un pod con Cassandra su un singolo nodo del cluster sarà problematico.

5. Backup

Vogliamo salvare una versione completa dei dati di un nodo Cassandra secondo un programma. Kubernetes fornisce una comoda opportunità utilizzando CronJob, ma qui Cassandra stessa ci crea problemi.

Ricordo che parte dei dati di Cassandra è archiviata in memoria. Per effettuare un backup completo, è necessario trasferire i dati dalla memoria (Memtables) su disco (SSTables). In questo momento il nodo Cassandra smette di accettare connessioni, disattivandosi completamente dal lavoro del cluster.

Dopo di ciò, viene eseguita una copia di backup (snapshot) e viene salvato lo schema (chiave spazio). E qui si scopre che semplicemente avere un backup non ci aiuta: è necessario salvare gli identificatori dei dati per cui era responsabile il nodo Cassandra, ovvero token speciali.

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

Un esempio di script per effettuare un backup di Cassandra da Google in Kubernetes può essere trovato su questo link. L'unico punto che lo script non considera è il ripristino dei dati nel nodo prima di eseguire lo snapshot. Quindi, il backup viene eseguito non per lo stato attuale, ma per uno stato precedente. Ma questo aiuta a non disattivare il nodo, il che appare molto logico.

set -eu

if [[ -z "$1" ]]; then
  info "Si prega di fornire una chiave spazio"
  exit 1
fi

KEYSPACE="$1"

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

if [[ $? -ne 0 ]]; then
  echo "Errore durante la creazione dello snapshot"
  exit 1
fi

timestamp=$(echo "$result" | awk '/Directory di snapshot: / { 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}"

Esempio di script bash per effettuare un backup da un nodo Cassandra

Soluzioni pronte per Cassandra in Kubernetes

Cosa si utilizza attualmente per implementare Cassandra in Kubernetes e quale di queste opzioni è più adatta ai requisiti specificati?

1. Soluzioni basate su StatefulSet o chart Helm

Utilizzare le funzionalità di base di StatefulSets per avviare un cluster Cassandra è una buona opzione. Con un chart Helm e i modelli Go, è possibile fornire all'utente un'interfaccia flessibile per l'implementazione di Cassandra.

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

Rappresentanti:

Entrambi i chart sono validi, ma sono soggetti ai problemi descritti in precedenza.

2. Soluzioni basate su Kubernetes Operator

Queste opzioni sono più interessanti perché offrono ampie possibilità di gestione del cluster. Per progettare un operatore Cassandra, come per qualsiasi altro database, un buon modello appare come Sidecar Controller CRD:

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

Consideriamo gli operatori esistenti.

1. Cassandra-operator di instaclustr

  • GitHub
  • Pronto: Alpha
  • Licenza: Apache 2.0
  • Realizzato in: Java

Questo è un progetto davvero promettente e in rapida espansione da parte di un'azienda che offre distribuzioni gestite di Cassandra. Come descritto sopra, utilizza un contenitore sidecar che riceve comandi tramite HTTP. È scritto in Java, quindi a volte manca di funzionalità più avanzate della libreria client-go. Inoltre, l'operatore non supporta diversi rack per un centro dati.

Tuttavia, l'operatore ha vantaggi come il supporto per il monitoraggio, la gestione del cluster a livello elevato tramite CRD e persino documentazione per la creazione di backup.

2. Navigator di Jetstack

  • GitHub
  • Pronto: Alpha
  • Licenza: Apache 2.0
  • Realizzato in: Golang

Operatore progettato per il deployment di DB-as-a-Service. Attualmente supporta due database: Elasticsearch e Cassandra. Include soluzioni interessanti, come il controllo degli accessi al database tramite RBAC (per questo viene sollevato un proprio navigator-apiserver separato). Un progetto interessante da tenere d'occhio, anche se l'ultimo commit risale a un anno e mezzo fa, il che ne riduce chiaramente il potenziale.

3. Cassandra-operator di vgkowski

  • GitHub
  • Pronto: Alpha
  • Licenza: Apache 2.0
  • Realizzato in: Golang

Non è stato preso in considerazione «seriamente», poiché l'ultimo commit nel repository risale a più di un anno fa. Lo sviluppo dell'operatore è stato abbandonato: l'ultima versione di Kubernetes dichiarata come supportata è 1.9.

4. Cassandra-operator di Rook

  • GitHub
  • Pronto: Alpha
  • Licenza: Apache 2.0
  • Realizzato in: Golang

Operatore il cui sviluppo non procede con la rapidità desiderata. Ha una struttura CRD ben progettata per la gestione del cluster e risolve il problema dell'identificazione dei nodi usando Service con ClusterIP (quel «hack»), ma per ora è tutto. Attualmente mancano monitoraggio e backup di default (a proposito, per il monitoraggio ci siamo presi noi). È interessante notare che con questo operatore è possibile anche deployare ScyllaDB.

NB: Questo operatore, con alcune modifiche, è stato utilizzato in uno dei nostri progetti. Non sono stati riscontrati problemi nel funzionamento dell'operatore durante il periodo di utilizzo (~4 mesi di attività).

5. CassKop di Orange

  • GitHub
  • Pronto: Alpha
  • Licenza: Apache 2.0
  • Realizzato in: Golang

Il più giovane operatore della lista: il primo commit è stato effettuato il 23 maggio 2019. Attualmente ha già a disposizione un gran numero di funzionalità dalla nostra lista, che possono essere consultate nel repository del progetto. L'operatore è costruito sulla base del popolare operator-sdk. Supporta il monitoraggio "out of the box". La principale differenza rispetto agli altri operatori è l'utilizzo del plugin CassKop, implementato in Python e utilizzato per la comunicazione tra i nodi di Cassandra.

Conclusioni

Il numero di approcci e possibili varianti per migrare Cassandra su Kubernetes parla chiaro: il tema è molto richiesto.

In questa fase, provare quanto descritto sopra è a proprio rischio e pericolo: nessuno degli sviluppatori garantisce il 100% di funzionamento della propria soluzione in un ambiente di produzione. Ma già ora molti prodotti sembrano promettenti per essere provati in ambienti di sviluppo.

Penso che in futuro questa donna a bordo sarà utile!

P.S.

Leggete anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS | ProHoster