Gluster-Cluster hegen und pflegen (Linux Magazin)

Wenn Gluster nicht mehr tut, wie es soll, ist der Ausfall eines damit umgesetzten File-Servers ärgerlich. Schmerzhaft wird es, wenn Gluster das Storage-Rückgrat einer Virtualisierungslösung ist.

Gluster eignet sich hervorragend als fehlertolerantes Storage-Backend für einen Hypervisor wie oVirt. Damit haben aber auch Probleme und Ausfälle in Gluster besondere Auswirkungen auf den Betrieb. Ein mit sich selbst beschäftigter Gluster im inkonsistenten Zustand kann darauf laufende VMs massiv in ihrer Performance beeinträchtigen. Als Admin steht man dann unter besonders starkem Druck und fragt sich, was zu tun ist und welche Folgen die Ausführung eines Kommandos haben kann, will man nicht in Minuten um Jahre altern. Eine kleine Auswahl.

Die Lernkurve ist nicht so steil wie bei Ceph: wer Gluster einsetzt, muss zunächst nur einige wenige Konzepte und Begriffe kennen.

  • Die Teilnehmer eines Gluster-Clusters bilden einen „Trusted Server

    Pool“ (TSP) und werden Host, Node oder Peer genannt.

  • Die in Gluster eingebundenen Disks mit ihren Partitionen und

    Dateisystemen heissen „Bricks“.

  • Bricks können lokal oder idealerweise über das Netzwerk mit je

    eigenem TCP-Port eingebunden werden.

  • Zwei oder mehr Bricks werden zu einem Gluster-„Volume“

    zusammengefasst.

  • Gluster kann Daten n-fach repliziert über die Bricks verteilt ablegen

    und lesen.

Da Gluster also einzelne, bestehende Dateisysteme zu einem oder mehreren Volumes kombiniert, ist es kein Dateisystem im eigentlichen Sinne, auch wenn das „FS“ in „GlusterFS“ anderes vermuten lässt.

Seit Anfang April 2019 ist Gluster 6 ab CentOS 6 und höher verfügbar und kann auf CentOS 7 wie folgt installiert werden:

yum install centos-release-gluster
yum install glusterfs-server
systemctl enable glusterd
systemctl start glusterd

oVirt 4 verlangt nach der älteren Version 3.12 (offiziell EOL), welches über die oVirt-Repos bezogen wird.

Ein Volume namens data mit drei Disks, die jeweils auf einem Host liegen, mit dreifacher Redundanz und ohne weitere Optimierungen, ist schnell eingerichtet.

Auf host1:

gluster peer probe host2
gluster peer probe host3

gluster volume create data replica 3 \
  host1:/gluster/brick/data \
  host2:/gluster/brick/data \
  host3:/gluster/brick/data
gluster volume start data

Hausaufgaben

Wer Gluster verteilt betreibt, kommt um zwei Voraussetzungen nicht herum: korrekte DNS-Einträge für die Gluster-Nodes (Forward und Reverse) sowie ein zuverlässiges NTP-Setup. Für den Fall, dass die DNS-Infrastruktur nicht verfügbar ist, sollte der Admin vorsichtshalber alle beteiligten Gluster-Nodes in der /etc/hosts eintragen.

Gegen den Reflex - Host-Firewalls abschalten

Host-Firewalls sind super - ausser wenn sie stören. Da die Gluster-Nodes meist in einer vertrauenswürdigen Umgebung laufen, sollte man deren lokale Firewalls deaktivieren. Was sich im ersten Moment unvernünftig anhört, hat einen handfesten Grund: Storage-Server sollen Daten schnell und vor allem zuverlässig verarbeiten können. Sind durch eine versehentlich aktivierte und falsch konfigurierte Host-Firewall Bricks auf ihren Netzwerk-Ports nicht erreichbar, kann das zur Inkonsistenz und im schlimmsten Fall zum Ausfall des Storage-Systems führen. Messbare Performance-Zuwächse oder Entlastung der Nodes durch das Abschalten der Host-Firewall sind dagegen kaum zu erwarten.

Für den Fall, dass die Firewall aus Versehen aktiviert wird, sollte sie so tolerant und auskunftsfreudig wie möglich konfiguriert werden:

firewall-cmd --set-log-denied=all
firewall-cmd --permanent --zone=public --add-source=192.168.100.0/24
firewall-cmd --permanent --zone=public --add-port=1-65535/tcp
firewall-cmd --permanent --zone=public --add-port=1-65535/udp
firewall-cmd --reload
firewall-cmd --list-all
systemctl stop firewalld
systemctl disable firewalld

Mein Name ist Bond

Falls die Kommunikation zwischen den Gluster-Nodes zickt oder die VMs auf dem Hypervisor nicht funktionieren, sollte man prüfen, ob und in welcher Form Bonding-Interfaces eingesetzt werden. Falls ja, sollte dem Bonding-Mode besondere Aufmerksamkeit geschenkt werden: er hängt davon ab, ob Gluster dediziert auf den Hosts zum Einsatz kommt (egal ob virtuell oder auf Bare Metal), oder ob Gluster sich die Maschine mit einem Hypervisor wie Red Hat Enterprise Virtualization (RHEV) oder dessen Upstream-Pendant oVirt teilen muss und eine „Hyperconverged Infrastructure“ bildet.

Das Gluster-Projekt empfiehlt für die Gluster-Nodes zunächst einmal den Bonding-Mode 6 (Adaptive Load Balancing, balance-alb). Damit können Clients die meisten Schreibanfragen parallel über alle verbundenen Netzwerk-Interfaces der Gluster-Nodes senden. Das Problem: Bonding Mode 6 kann nicht zusammen mit Bridges verwendet werden, und ist daher nicht mit logischen Netzwerken in VMs kompatibel. Wer also eine Hyperconverged Infrastruktur betreibt, setzt bei oVirt/RHEV auf den dort empfohlenen Bonding Mode 4 (IEEE 802.3ad policy).

Auch schon vorgekommen: ein Switch war fälschlicherweise der Meinung, dass sich die Interface-Geschwindigkeit von beispielsweise 10 Gbps auf 1 Gbps geändert hat, und handelte die Verbindung neu aus - um sich kurz danach wieder umzuentscheiden. Ein Node im stark ausgelasteten Gluster-Cluster wurde dadurch zweimal kurz abgehängt, was anschliessend zur Synchronisation und noch stärkerer Auslastung führte. Man kann sich daher überlegen, auf dem Switch die Geschwindigkeit der Netzwerk-Interfaces fix auf den zu erwartenden Wert einzustellen.

Jumbo-Performance

Jumbo-Frames sind ein oft eingesetztes Mittel, um den Netzwerkdurchsatz signifikant zu steigern. Wer mit Netzwerkproblemen zwischen den Gluster-Nodes zu kämpfen hat, sollte daher prüfen, ob Jumbo-Frames aktiviert sind und noch funktionieren.

Jumbo-Frames sind aktiv, wenn die Gluster-Nodes über ip a | grep mtu eine MTU grösser als 1500 melden, üblicherweise 9000. Allerdings müssen auch alle dazwischen liegenden Netzwerkkomponenten Jumbo-Frames unterstützen. Das Senden überlanger Frames von einem Gluster-Node zum nächsten testet man mit ping -s 1600 -M do <gluster-node-n>, wobei -s die Paketgrösse ohne Header festlegt, und -M do die Fragmentierung auf dem Weg zum Empfänger verhindert.

yum

Falls das erste Mal yum update auf einem Node ausgeführt wird, kann die Fehlermeldung „GPG key retrieval failed: [Errno 14] Could not open/read file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-auxiliary“ für Unbehagen sorgen, aber getrost ignoriert werden; beim zweiten Aufruf von yum update wird die Meldung nicht mehr erscheinen.

Schlimmer wird es, wenn nach einem yum update ein Gluster-Host zwar noch erreichbar ist, aber dessen Bricks nicht mehr. Hier hilft eine schnelle Analyse der Log-Files. So wurden schon Shared Object Libraries (.so-Dateien) entfernt, die je nach Konfiguration für den Betrieb von Gluster notwendig sind, was sich in den Log-Dateien in der Art /usr/lib64/glusterfs/3.12.6/rpc-transport/rdma.so: cannot open shared object file: No such file or directory äussert. Wer in diesem Fall auf RDMA, also Speicherdirektzugriff über das Netzwerk, verzichten kann, deaktiviert RDMA in der /etc/glusterfs/glusterd.vol und startet den Gluster-Daemon neu.

Nach einem Update darauf achten: wer die Host-Firewall auf seinen Gluster-Nodes deaktiviert hatte, sollte vor einem Reboot prüfen, ob sie immer noch deaktiviert ist.

Selbstheilungsmechanismus

Der Gluster-Cluster befindet sich in einem inkonsistenten Zustand? Wer sich wundert, wann der Gluster „Self-heal Daemon“ (glustershd) endlich mit dem Selbstheilungsprozess beginnt, wirft einen Blick in das Setting gluster volume get <volname> cluster.heal-timeout, was standardmässig auf 600 Sekunden steht - im Produktivbetrieb meiner Meinung nach zu lang, in der Zeit laufen die Bricks zu stark auseinander. Um den Mechanismus von Hand anzustossen, genügt der Aufruf von gluster volume heal <volname>, der Fortschritt wird mit gluster volume heal <volname> info überwacht. Viele Volume-Settings lassen sich übrigens zur Laufzeit ändern, ohne die Gluster-Daemons neu starten zu müssen. Ist das Self-Healing angestossen, heisst es, sich in Geduld zu üben. Ein Beispiel für Shards im inkonsisten Zustand zeigt Kasten XXX.

Je nach Grad der Replikation hat ein inkonsistenter Zustand oder die Replikation keine Auswirkungen auf die Datenintegrität, jedoch auf die Performance angeschlossener Clients oder VMs, denn ähnlich einem klassischen RAID wird Gluster die inhaltlich auseinandergelaufenen Bricks synchronisieren. Die Load geht dabei teilweise extrem hoch, limitierender Faktor ist in fast allen Fällen I/O, also Disk und/oder Netzwerk. kernel:NMI watchdog: BUG: soft lockup - CPU#0 stuck for 22s! oder ata2.00: exception Emask 0x0 ... frozen sind die typischen Kernel Ring Buffer-Meldungen, die VMs produzieren, wenn sie auf hochausgelasteten Gluster-Systemen laufen, z.B. in einem Hyperconverged-Setup.

Für die Ablage von VM-Disks wird Gluster in der Regel so konfiguriert, dass es „Shards“ verwendet - eine grosse VM-Disk wird so in kleinere Häppchen fixer Grösse aufgeteilt und gleichmässig auf die Gluster-Nodes repliziert und verteilt. Die Gluster-Bricks sind damit in der Lage, nur die gerade angeforderten oder sich ändernden Bereiche einer VM-Disks sequentiell zu lesen bzw. zu schreiben, was die Geschwindigkeit erhöht.

Je nachdem, welcher Anleitung man zu welchem Zeitpunkt gefolgt ist, werden zu grosse Shards verwendet. Shards mit beispielsweise 512 MB Grösse verringern zwar die Anzahl der zu verwaltenden Dateien im Gluster-Volume, führen aber dazu, dass bei der kleinsten Änderung in der VM-Disk jeweils 512 MB gelesen, geschrieben oder repliziert werden müssen, was den Heal-Prozess verlangsamt. Das Gluster-Projekt empfiehlt, 64 MB grosse Shards einzusetzen. Die für ein Volume gesetzte Shard-Grösse lässt sich mit gluster volume get <volname> features.shard-block-size abfragen. Eine nachträgliche Änderung ist nicht möglich - dazu muss das Volume neu aufgesetzt werden.

Wer das Gefühl hat, dass das Healing kein Ende nimmt, hält nach sich wiederholenden UUIDs (also Zeichenktten der Form „14fb48a6-c192-4c3f-a588-44c80cc36711“) im Gluster Self Heal Daemon Log sowie den Brick-Logs Ausschau. Shards erhalten eine UUID; zusammenhängende Shards werden um eine fortlaufende Nummer ergänzt. Die Datei .shard/14fb48a6-c192-4c3f-a588-44c80cc36711.3599 ist der 3599ste Shard einer VM-Disk. Tauchen immer wieder die gleichen Shard-UUIDs auf, dann schreibt eine VM, und Gluster kommt aufgrund von Last, limitierter Disk- oder Netzwerkbandbreite nicht mit der Synchronisation auf die anderen Nodes hinterher. Hier hilft es, die VMs zu identifizieren und herunterzufahren.

Migration

Um Bricks von einem Host zum anderen zu verschieben, wird gluster replace-brick genutzt. Dabei werden keinerlei Daten vom alten Brick auf den neuen Brick kopiert oder verschoben. Gluster macht es sich viel einfacher: der alte Brick wird abgehängt, und der neue durch den Self-heal-Daemon repariert. Es empfiehlt sich also, das Healing sofort nach replace-brick anzustossen. Die derzeit korrekte Form des Kommandos lautet gluster volume replace-brick <volname> host1:/gluster/brick/data host4:/gluster/brick/data commit force.

Wer VMs von einer Storage-Domain auf eine andere umziehen möchte, arbeitet am besten mit den Bordmitteln seiner Virtualisierungslösung, z.B. mit der Weboberfläche der oVirt-Engine. Nach Möglichkeit sollten nur ausgeschaltete VMs migriert werden - das ist bedeutend schneller und weniger fehleranfällig, insbesondere bei Servern, die irgendeine Form von Datenbanksystem fahren. oVirt erzeugt beim Umzug eingeschalteter VMs zunächst einen Snapshot der Maschine, verschiebt die Disk, und führt am Ende die migrierte Disk und den Snapshot zusammen. Bei ausgeschalteter VM wird deren Disk dagegen einfach nur von oVirt verschoben. Das Vorgehen hat zwar überhaupt nichts mit Gluster an sich zu tun, funktioniert aber hier auch nicht besser oder schlechter als bei auf anderen Techniken basierenden Storage-Domains.

Nicht mehr verwendete, gestoppte Volumes können mit gluster volume delete <volname> gelöscht werden. Die Daten auf den Bricks bleiben erhalten.

Split Brain

Gluster ist kaum aus dem Tritt zu bringen: in seinen Replikationsmodi und mit Hilfe seiner Self-heal Daemons läuft es bewundernswert stabil. Schlimm wird es, wenn der Aufruf von gluster volume heal <volname> info Meldungen in der Form

Brick host7:/gluster/brickf/data
/.shard/40643186-66de-4e2d-900a-b2bdcc762cdc.1000 - Is in split-brain

Brick host9:/gluster/arb2/data
/.shard/40643186-66de-4e2d-900a-b2bdcc762cdc.1000 - Is in split-brain

bringt. Einfachstes Beispiel für „Split Brain“ sind zwei sich replizierende Nodes, die untereinander getrennt werden, jedoch weiterlaufen und Schreibanfragen von aussen beantworten können. Werden die Nodes wieder zusammengeführt, ist die Datenintegrität verloren.

Gluster wird Split Brain-Dateien zunächst einmal nicht selbständig reparieren, hier muss der Admin ran. Falls eine VM betroffen ist, muss diese vorher heruntergefahren werden (Poweroff). Zur Lösung jedes einzelnen Split Brain-Problems gibt es drei Möglichkeiten:

  1. Man entscheidet sich für die Datei, die zuletzt geändert wurde:

    gluster volume heal <volname> split-brain latest-mtime <filename>

  2. Man wählt die grössere der beiden Dateien aus:

    gluster volume heal <volname> split-brain bigger-file <filename>

  3. Man bestimmt aus der Menge an Bricks, die diese Datei führen, einfach einen Brick als Quelle zur Wiederherstellung:

    gluster volume heal <volname> split-brain source-brick <host:brickname>

Die Dateien untersucht man auf den betroffenen Hosts mit stat <filename>, um eine Entscheidungsgrundlage zu haben.

Wer dagegen weiss, dass es beispielsweise immer auf die neueste Datei ankommt, kann Gluster auch zur automatischen Korrektur von Split Brains bewegen. Standardmässig steht die Einstellung cluster.favorite-child-policy auf none, lässt sich aber analog zur obigen Aufzählung auf mtime, ctime oder size setzen. Die Policy majority verwendet die Dateiversion als Quelle, die mit identischer mtime und size auf mehr als der Hälfte aller Bricks vorkommt.

Monitoring

Gluster bietet wesentlich mehr als die klassische Logfile-Überwachung. Mit dem gluster-Befehl kann man sich unter anderem Statusinformationen zu Volumes, Bricks oder Self-heal Daemons anzeigen lassen oder Volumes debuggen. gluster kann unter anderem folgende Fragen beantworten:

  • Welche Volumes gibt es?

    gluster volume list

  • Sind die Bricks der Volumes online, laufen die Self-heal Daemons?

    gluster volume status all

  • Wie steht es um den Plattenplatz der Bricks, freie Inodes usw.?

    for volname in gluster volume list; do gluster volume status $volname detail; done

  • Wer greift auf das Volume zu?

    gluster volume status <volname> clients

  • Wie fällt der Memory-Verbrauch der Bricks aus?

    gluster volume status <volname> mem

Fazit

So einfach sich Gluster installieren lässt, bedarf es - wie jedes andere Storage-System auch - eine für den Einsatzzweck ausgelegte Konfiguration sowie laufende Überwachung. Zudem sollte man einige Stolpersteine kennen und in Teilen wissen, wie Gluster unter der Haube arbeitet. Geplante Arbeiten sowie Troubleshooting lassen sich an kleinen virtuellen Testsystemen üben. Das wichtigste im Ernstfall ist aber, auch unter Druck Ruhe zu bewahren und besonnen die nächsten Schritte durchzuführen.

Der Autor

Markus Frei ist Mitinhaber der Linuxfabrik GmbH in Zürich, die Service & Support für Linux und Open Source Applikationen sowie Managed Hosting in einem Schweizer T4-Datacenter anbietet. Ihr Produkt „Nextcloud as a Service“ (https://www.linuxfabrik.ch/nextcloud) als Alternative zu Dropbox oder Google Drive läuft unter oVirt und GlusterFS.


Kasten: Restart des glusterd

Ein systemctl restart glusterd führt dazu, dass der Node und dessen Bricks kurzzeitig abgehängt werden. Alle ab sofort im Gluster-Cluster stattfindenden Schreibvorgänge werden protokolliert und, sobald der Node wieder verfügbar und die Selbstheilung angestossen ist, synchronisiert, was je nach Schreiblast und Infrastruktur Stunden in Anspruch nehmen kann. Wird glusterd auf dem Host neu gestartet, mit dem man per FUSE-Mount verbunden ist, geht kurz die Verbindung verloren.

Kasten: Netzwerk-Ports auf einem Gluster-Node mit vier aktiven Bricks

Address:Port  Peer Address:Port
*:24007       users:(("glusterd",pid=9518,fd=10))
*:49152       users:(("glusterfsd",pid=10063,fd=11))
*:49153       users:(("glusterfsd",pid=10069,fd=11))
*:49154       users:(("glusterfsd",pid=10081,fd=11))
*:49155       users:(("glusterfsd",pid=10087,fd=11))

Kasten XXX: Gluster-Brick in zwei verschiedenen Zuständen

# konsistent
Brick host42:/gluster/arb2/data
Status: Connected
Number of entries: 0

# inkonsistent
Brick host42:/gluster/arb2/data
/.shard/6aa1460a-298b-45b9-972d-39dfc4400ac1.35
/.shard/6aa1460a-298b-45b9-972d-39dfc4400ac1.82
/.shard/6aa1460a-298b-45b9-972d-39dfc4400ac1.30
/.shard/6aa1460a-298b-45b9-972d-39dfc4400ac1.93
/.shard/6aa1460a-298b-45b9-972d-39dfc4400ac1.18
Status: Connected
Number of entries: 5

Kasten: die hilfreichsten Gluster-Logfiles auf CentOS 7

  • Gluster Daemon:

    /var/log/gluster/glusterd.log

  • Gluster Self-heal Daemon:

    /var/log/gluster/glustershd.log

  • Gluster Bricks:

    /var/log/glusterfs/bricks/gluster-<brickname>-<volname>.log