
Wir begegnen regelmäßig der Apache Cassandra-Datenbank und der Notwendigkeit, sie im Rahmen der auf Kubernetes basierenden Infrastruktur zu betreiben. In diesem Artikel werden wir unsere Vision der notwendigen Schritte, Kriterien und vorhandenen Lösungen (einschließlich einer Übersicht der Bediener) für die Migration von Cassandra zu K8s teilen.
„Wer eine Frau kontrollieren kann, kommt mit dem Staat klar“
Wer ist Cassandra? Es handelt sich um ein verteiltes Speichersystem, mit dem große Datenmengen verwaltet und gleichzeitig eine hohe Verfügbarkeit ohne einen einzigen Ausfallpunkt gewährleistet werden kann. Das Projekt braucht kaum eine lange Einführung, deshalb werde ich nur die Hauptmerkmale von Cassandra nennen, die im Zusammenhang mit einem bestimmten Artikel relevant sind:
- Cassandra ist in Java geschrieben.
- Die Cassandra-Topologie umfasst mehrere Ebenen:
- Knoten - eine bereitgestellte Instanz von Cassandra;
- Rack - Eine Gruppe von Cassandra-Instanzen, die durch ein Attribut in einem Rechenzentrum zusammengefasst sind.
- Rechenzentrum - die Gesamtheit aller Gruppen von Cassandra-Instanzen in einem Rechenzentrum;
- Cluster - eine Sammlung aller Rechenzentren.
- Cassandra verwendet eine IP-Adresse, um den Host zu identifizieren.
- Um Lese- und Schreibvorgänge zu beschleunigen, speichert Cassandra einen Teil der Daten im RAM.
Nun zum eigentlichen möglichen Wechsel zu Kubernetes.
Checkliste für die Migration
Wenn wir über die Migration von Cassandra nach Kubernetes sprechen, hoffen wir, dass es bequemer wird, sie mit dem Umzug zu verwalten. Was wird dafür benötigt, was hilft dabei?
1. Datenspeicherung
Wie bereits angegeben, speichert
Cassanda einen Teil der Daten im RAM - in
Memtable . Es gibt jedoch noch ein anderes Datenelement, das auf der Festplatte gespeichert wird - in Form von
SSTable . Zu diesen Daten wird das Entity
Log Log hinzugefügt - Aufzeichnungen aller Transaktionen, die ebenfalls auf der Festplatte gespeichert sind.
Cassandra Write Transaction SchemeIn Kubernetes können wir PersistentVolume zum Speichern von Daten verwenden. Dank gut entwickelter Mechanismen wird die Arbeit mit Daten in Kubernetes von Jahr zu Jahr einfacher.
Für jeden Pod mit Cassandra ordnen wir unser PersistentVolume zuEs ist wichtig zu beachten, dass Cassandra selbst die Datenreplikation impliziert und dafür eingebaute Mechanismen bietet. Wenn Sie einen Cassandra-Cluster aus einer großen Anzahl von Knoten erstellen, müssen Sie daher keine verteilten Systeme wie Ceph oder GlusterFS zum Speichern von Daten verwenden. In diesem Fall ist es logisch, Daten auf dem Host-Datenträger mit
lokalen persistenten Datenträgern zu speichern oder
hostPath
.
Eine weitere Frage ist, ob Sie für jeden Feature-Zweig eine eigene Entwicklungsumgebung erstellen möchten. In diesem Fall wäre der richtige Ansatz, einen Cassandra-Knoten auszulösen und die Daten in einem verteilten Speicher zu speichern, d. H. Erwähntes Ceph und GlusterFS sind Ihre Wahl. Dann ist der Entwickler sicher, dass er auch dann keine Testdaten verliert, wenn einer der Knoten des Kuberntes-Clusters verloren geht.
2. Überwachung
Prometheus ist für die Überwachung in Kubernetes praktisch keine Alternative
(darüber haben wir im entsprechenden Bericht ausführlich gesprochen) . Wie geht es Cassandra mit metrischen Exporteuren für Prometheus? Und was ist in gewisser Weise noch wichtiger, mit Dashboards, die für Grafana geeignet sind?
Ein Beispiel für die Darstellung von Diagrammen in Grafana für CassandraEs gibt nur zwei Exporteure:
jmx_exporter und
cassandra_exporter .
Wir haben die erste für uns ausgewählt, weil:
- JMX Exporter wächst und entwickelt sich, während Cassandra Exporter nicht in der Lage war, die richtige Community-Unterstützung zu erhalten. Cassandra Exporter unterstützt die meisten Versionen von Cassandra immer noch nicht.
- Sie können es als javaagent ausführen, indem Sie das Flag -javaagent hinzufügen
-javaagent:<plugin-dir-name>/cassandra-exporter.jar=--listen=:9180
. - Für ihn gibt es ein passendes Dashboad , das mit Cassandra Exporter nicht kompatibel ist.
3. Auswahl von Kubernetes-Primitiven
Entsprechend der obigen Struktur des Cassandra-Clusters werden wir versuchen, alles, was dort beschrieben wird, in die Kubernetes-Terminologie zu übersetzen:
- Cassandra Node → Pod
- Cassandra Rack → StatefulSet
- Cassandra Datacenter → Pool von StatefulSets
- Cassandra Cluster → ???
Es stellt sich heraus, dass eine zusätzliche Entität fehlt, um den gesamten Cassandra-Cluster auf einmal zu verwalten. Aber wenn etwas nicht da ist, können wir es schaffen! Kubernetes verfügt über eine dedizierte Ressourcendefinitions-Engine namens "
Benutzerdefinierte Ressourcendefinitionen" .
Ankündigung zusätzlicher Ressourcen für Protokolle und WarnungenEine benutzerdefinierte Ressource allein bedeutet jedoch nichts: Sie benötigen einen
Controller dafür. Möglicherweise müssen Sie auf die Hilfe eines
Kubernetes-Betreibers zurückgreifen ...
4. Identifizierung der Hülsen
Im obigen Punkt haben wir vereinbart, dass ein Cassandra-Knoten einem Pod in Kubernetes entspricht. Die IP-Adressen des Pods sind jedoch jedes Mal anders. Und die Knotenidentifikation in Cassandra erfolgt genau anhand der IP-Adresse ... Es stellt sich heraus, dass der Cassandra-Cluster nach jedem Entfernen des Pods einen neuen Knoten hinzufügt.
Es gibt einen Ausweg und nicht einmal einen:
- Wir können Aufzeichnungen nach Host-IDs (UUIDs, die Cassandra-Instanzen eindeutig identifizieren) oder nach IP-Adressen führen und dies in einigen Strukturen / Tabellen speichern. Das Verfahren hat zwei Hauptnachteile:
- Das Risiko eines Rennzustands, wenn zwei Knoten gleichzeitig fallen. Nach dem Upgrade fordern die Cassandra-Knoten gleichzeitig eine IP-Adresse für sich selbst aus der Tabelle an und konkurrieren um dieselbe Ressource.
- Wenn der Cassandra-Knoten seine Daten verloren hat, können wir sie nicht mehr identifizieren.
- Die zweite Lösung scheint ein kleiner Hack zu sein, aber dennoch: Wir können einen Service mit ClusterIP für jeden Cassandra-Knoten erstellen. Probleme mit dieser Implementierung:
- Wenn ein Cassandra-Cluster viele Knoten enthält, müssen viele Dienste erstellt werden.
- Die ClusterIP-Funktion wird über iptables implementiert. Dies kann ein Problem sein, wenn der Cassandra-Cluster viele (1000 ... oder sogar 100?) Knoten hat. Ein auf IPVS basierendes Balancing kann dieses Problem zwar lösen.
- Die dritte Lösung ist die Verwendung eines Knotennetzwerks für Cassandra-Knoten anstelle eines dedizierten Pod-Netzwerks, indem die Einstellung
hostNetwork: true
. Diese Methode unterwirft bestimmte Einschränkungen:
- Knoten ersetzen. Es ist erforderlich, dass der neue Host dieselbe IP-Adresse wie der vorherige Host hat (in Clouds wie AWS oder GCP ist dies fast unmöglich).
- Unter Verwendung des Netzwerks von Clusterknoten beginnen wir, um Netzwerkressourcen zu konkurrieren. Daher ist es problematisch, mit Cassandra auf einem Clusterknoten mehr als einen Pod zu installieren.
5. Backups
Wir möchten die Vollversion der Daten für einen Cassandra-Knoten nach einem Zeitplan aufbewahren. Kubernetes bietet mit
CronJob eine bequeme Möglichkeit, aber hier steckt Cassandra die Stöcke in die Räder.
Lassen Sie mich daran erinnern, dass ein Teil der Daten von Cassandra im Speicher abgelegt wird. Um eine vollständige Sicherung zu erstellen, müssen Sie Daten vom Speicher (
Memtables ) auf die Festplatte (
SSTables ) übertragen. Zu diesem Zeitpunkt akzeptiert der Cassandra-Knoten keine Verbindungen mehr und fährt den Cluster vollständig herunter.
Danach wird ein Backup (
Snapshot ) entfernt und das Schema (
Keyspace )
gespeichert . Und dann stellt sich heraus, dass nur eine Sicherung nichts bringt: Sie müssen die Daten-IDs speichern, für die der Cassandra-Knoten verantwortlich war - dies sind spezielle Token.
Token-Verteilung, um zu identifizieren, welche Daten für die Cassandra-Knoten verantwortlich sindEin Beispielskript zum Entfernen von Cassandra aus Google in Kubernetes finden Sie unter
diesem Link . Der einzige Punkt, den das Skript nicht berücksichtigt, ist das Speichern der Daten auf dem Knoten, bevor der Snapshot entfernt wird. Das heißt, die Sicherung erfolgt nicht für den aktuellen Status, sondern für den Status etwas früher. Dies hilft jedoch, den Knoten nicht aus der Arbeit zu bringen, was sehr logisch erscheint.
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}"
Beispiel für ein Bash-Skript zum Entfernen der Sicherung von einem einzelnen Cassandra-KnotenVorgefertigte Lösungen für Cassandra in Kubernetes
Was verwenden sie derzeit, um Cassandra in Kubernetes bereitzustellen, und welches davon ist für die gegebenen Anforderungen am besten geeignet?
1. StatefulSet- oder Helm Chart-Lösungen
Die Verwendung der grundlegenden StatefulSets zum Starten eines Cassandra-Clusters ist eine gute Option. Mit den Vorlagen Helm-Diagramm und Go können Sie dem Benutzer eine flexible Oberfläche für die Bereitstellung von Cassandra bereitstellen.
Normalerweise funktioniert dies einwandfrei ... bis etwas Unerwartetes passiert - zum Beispiel ein Knoten fällt aus. Die Standard-Kubernetes-Tools können einfach nicht alle oben genannten Funktionen berücksichtigen. Darüber hinaus ist dieser Ansatz sehr begrenzt, da er für komplexere Zwecke erweitert werden kann: Austausch von Knoten, Sicherung, Wiederherstellung, Überwachung usw.
Vertreter:
Beide Diagramme sind gleich gut, aber anfällig für die oben beschriebenen Probleme.
2. Lösungen basierend auf Kubernetes Operator
Solche Optionen sind interessanter, da sie umfangreiche Funktionen zur Clusterverwaltung bieten. Um eine Cassandra-Anweisung wie jede andere Datenbank zu entwerfen, sieht ein gutes Muster aus wie Sidecar <-> Controller <-> CRD:
Knotenverwaltungsdiagramm in einer ordnungsgemäß gestalteten Cassandra-AnweisungBerücksichtigen Sie die vorhandenen Operatoren.
1. Cassandra-Operator von instaclustr
- Github
- Bereitschaft: Alpha
- Lizenz: Apache 2.0
- Implementiert in: Java
Dies ist in der Tat ein vielversprechendes und sich schnell entwickelndes Projekt eines Unternehmens, das von Cassandra verwaltete Bereitstellungen anbietet. Wie oben beschrieben, wird ein Sidecar-Container verwendet, der Befehle über HTTP akzeptiert. Es ist in Java geschrieben, daher fehlt manchmal die erweiterte Funktionalität der Client-Go-Bibliothek. Der Bediener unterstützt auch keine unterschiedlichen Racks für ein Rechenzentrum.
Der Bediener hat jedoch solche Vorteile wie Überwachungsunterstützung, Cluster-Management auf hoher Ebene mithilfe von CRD und sogar Dokumentation zum Entfernen von Sicherungen.
2. Navigator von Jetstack
- Github
- Bereitschaft: Alpha
- Lizenz: Apache 2.0
- Umgesetzt in: Golang
Eine Anweisung zum Bereitstellen von DB-as-a-Service. Unterstützt derzeit zwei Datenbanken: Elasticsearch und Cassandra. Es bietet so interessante Lösungen wie die Zugriffskontrolle auf die Datenbank über RBAC (hierfür wird ein eigener separater Navigator-Apiserver angehoben). Ein interessantes Projekt, das einen genaueren Blick wert wäre, aber das letzte Engagement wurde vor eineinhalb Jahren gemacht, was sein Potenzial deutlich reduziert.
3. Cassandra-Operator von vgkowski
- Github
- Bereitschaft: Alpha
- Lizenz: Apache 2.0
- Umgesetzt in: Golang
Sie betrachteten es nicht als „ernst“, da die letzte Übergabe an das Endlager vor mehr als einem Jahr erfolgte. Die Betreiberentwicklung wird eingestellt: Die neueste Version von Kubernetes, die als unterstützt deklariert wurde, ist 1.9.
4. Cassandra-Operator von Rook
- Github
- Bereitschaft: Alpha
- Lizenz: Apache 2.0
- Umgesetzt in: Golang
Ein Betreiber, dessen Entwicklung nicht so schnell vonstatten geht, wie wir es uns wünschen. Es verfügt über eine durchdachte CRD-Struktur für die Verwaltung des Clusters, löst das Problem der Identifizierung von Knoten mithilfe von Service mit ClusterIP (der gleiche "Hack") ... aber für den Moment ist das alles. Derzeit sind keine sofort einsatzbereiten Überwachungen und Backups verfügbar (wir haben übrigens damit begonnen, uns selbst
zu überwachen). Ein interessanter Punkt ist, dass Sie mit diesem Operator auch ScyllaDB bereitstellen können.
NB: Wir haben diesen Operator mit geringfügigen Änderungen in einem unserer Projekte verwendet. Während des gesamten Betriebs (~ 4 Monate Betriebsdauer) gab es keine Probleme bei der Arbeit des Bedieners.5. CassKop von Orange
- Github
- Bereitschaft: Alpha
- Lizenz: Apache 2.0
- Umgesetzt in: Golang
Der jüngste Betreiber auf der Liste: Die erste Übergabe erfolgte am 23. Mai 2019. Er hat bereits eine Vielzahl von Features aus unserer Liste in seinem Arsenal, von denen weitere Details im Projekt-Repository zu finden sind. Der Operator basiert auf dem beliebten Operator-SDK. Unterstützt die sofortige Überwachung. Der Hauptunterschied zu anderen Betreibern ist die Verwendung des in Python implementierten
CassKop-Plugins , das für die Kommunikation zwischen Cassandra-Knoten verwendet wird.
Schlussfolgerungen
Die Anzahl der Ansätze und möglichen Optionen für die Portierung von Cassandra auf Kubernetes spricht für sich: Das Thema ist gefragt.
In dieser Phase können Sie eine der oben genannten Methoden auf eigene Gefahr und Gefahr ausprobieren: Keiner der Entwickler garantiert eine 100% ige Arbeit seiner Lösung in der Produktionsumgebung. Aber jetzt sehen viele Produkte vielversprechend aus, um sie in Entwicklungsständen zu verwenden.
Ich denke, in Zukunft muss diese Frau auf dem Schiff gehen!
PS
Lesen Sie auch in unserem Blog: