Benutzer-Werkzeuge

Webseiten-Werkzeuge


freebsd:hast_best_practices

High Availability Storage (HAST) Best Practices

High Availability Storage oder kurz HAST ist ein System zur redundanten Speicherung von Daten. Es ist seit FreeBSD 7.0 Teil des FreeBSD Basissystems, kann mit anderen FreeBSD-Techniken wie zum Beispiel CARP und ZFS kombiniert werden. Dieser Artikel ist kein Howto und auch keine Dokumentation.

Die Dokumentation wird durch das FreeBSD Handbuch abgedeckt: https://www.freebsd.org/doc/handbook/disks-hast.html

Viel mehr sollen hier einige erfolgreiche Beispiele (Best Practice) aufgezeigt werden, die sich über mehrere Jahre produktiven Betriebs ergeben haben.

HAST ist grob nach Linux DRDB entworfen, deckt allerdings nur einen Teil des Umfangs ab. Es ist ein reines Master ↔ Slave System, jedes HAST-Setup besteht aus exakt 2 Nodes. Eine ist der aktive Master, der passive Slave repliziert lediglich die Daten. FreeBSD bietet mehrere Alternativen zu HAST, die je nach Situation geeigneter sein können:

  • gmultipath(4) ist eine High Level Implementierung von Disk Multipathing.
  • iSCSI von FreeBSD unterstützt High Availability Extension.
  • Derzeit (Juni 2016) gibt es experimentelle Unterstützung von glusterfs und pnfs.

Grundsätzliche Regeln im Umgang mit HAST

Die folgenden Regeln sind nicht dogmatisch zu betrachten, stattdessen beruhen sie auf den Erfahrungen des Autors. Andere Administratoren mögen andere Erfahrungen gemacht haben, was zu anderen Regeln führt.

  • Beide Nodes eines HAST-Setups sollten wenn möglich gleich sein. Wenn das nicht zu erreichen ist, sollte zumindest die Festplattenkonfiguration gleich sein. Wenn als Beispiel Node A 5 Festplatten mit 2TB hat, sollte auch Node B 5 Festplatten mit 2TB besitzen. Abweichende Festplattenkonfigurationen können im Fehlerfall katastrophale Auswirkungen haben, da sie Fehlbedienung stark begünstigen.
  • Beide Nodes sollten über eine dedizierte Verbindung miteinander kommunizieren, idealerweise über eine Back to Back Verbindung mit vom eigentlichen Netzwerk getrennten IP-Adressen. Sprich, diese Adressen sollten in einem eigenen Subnetz liegen, was so klein wie möglich gefasst ist. Die dedizierte Verbindung verhindert konkurrierenden Netzwerkverkehr, aber auch Fehler durch Fehlkonfiguration wie kollidierende IP-Adressen sind damit zumindest bis zum einem gewissen Punkt auszuschließen.
  • HAST sollte immer auf Partitionen genutzt werden, niemals auf rohen Devices. Die Partitionen sollten einige Megabyte kleiner als umgebende Device sein. Dies vereinfacht das Tauschen von Festplatten sehr, es verhindert effektiv Probleme mit geringfügig kleineren Tauschplatten.
  • In komplexeren Setups sollte HAST die oberste Technologie im Stack sein. Dies verhindert Probleme im Zusammenspiel mit anderen Technologien, die z.B. beim Umschalten zwischen den Nodes auftreten können.

Automatisches gegen manuelles Umschalten

Viel Dokumentation zu HAST empfiehlt es mit CARP zu kombinieren, somit einen Ausfall des Masters zu erkennnen und automatisch auf den Slave umzuschalten. Dies ist durchaus robust zu implementieren, allerdings ist es gerade in komplexeren Setups schwer alle möglichen Randfälle zu beachten. Wenn es möglich ist, ist es daher zu empfehlen, auf ein automatisches Umschalten zu verzichten und stattdessen einige Minuten Downtime für ein manuelles Umschalten in Kauf zu nehmen.

Ein Beispielsetup

Der Autor nutzt seit FreeBSD 9.2 HAST ausschließlich in Kombination mit ZFS. Eine Nutzung mit UFS ist natürlich möglich, allerdings ist bei einem Umschalten im Katastrophenfall ein vollständiges fsck ohne Nutzung des Journals zwingend notwendig. Ansonsten sind möglicherweise katastrophale Inkonsistenzen im Dateisystem nicht auszuschließen.

Zum Einsatz kommen zwei Maschinen mit jeweils 4 Festplatten. Für das Beispiel ist die genaue Hardware egal, in der Praxis ist Server-Hardware zu empfehlen. Beide Maschinen haben 2 Netzwerkkarten. igb0 bietet den Anschluss an das Netzwerk, igb1 ist eine Back to Back Verbindung zwischen den beiden Maschinen. Der Erfahrung nach reicht Gigabit-Ethernet für die Back to Back Verbingung aus, 10 Gigabit bringen keine besseren Latenzen, es können lediglich große Datenmengen schneller synchronisiert werden.

IP-Adresse Node A: 10.1.0.1
IP-Adresse Node B: 10.1.0.2

Partitionierung einer Platte, hier ist viel Platz freigelassen worden, da es sich um SSDs handelt. HAST überträgt TRIM-Kommandos, allerdings hat sich TRIM im Zusammenspiel mit dem Controller und den SSDs als problematisch erwiesen. Die Partitionen sind gelabelt, zhast01 ist Beispielsweise die Partition auf der SSD in Slot 1:

=>       34  937703021  da1  GPT  (447G)
         34          6       - free -  (3.0K)
         40  916455424    1  freebsd-zfs  (437G)
  916455464   21247591       - free -  (10G)

Die hast.conf entspricht weitgehend den Vorgaben. LZF-Kompression ist oftmals den geringen CPU-Overhead wert, da es die benötigte Bandbreite auf der Back to Back Verbindung merklich senkt und damit die Synchronisierung beschleunigt. In der hier genutzten Standardeinstellung gelten Daten als geschrieben, wenn sie auf dem Master ausgeschrieben und im RAM des Slave gespeichert wurden. fullsync verlangt, dass auch der Slave sie ausgeschrieben hat, dies ist zwar sicherer, aber auch bis zu dem Faktor 10 langsamer.

compression lzf 

resource zhast01 {
    on nodea.lan {
        local /dev/gpt/hast01
        remote tcp4://10.1.0.1
    }   
    on nodeb.lan {
        local /dev/gpt/hast01
        remote tcp://10.1.0.2
    }   
}

resource zhast02 {
    on nodea.lan {
        local /dev/gpt/hast02
        remote tcp4://10.1.0.1
    }   
    on nodeb.lan {
        local /dev/gpt/hast02
        remote tcp://10.1.0.2
    }   
}

resource zhast03 {
    on nodea.lan {
        local /dev/gpt/hast03
        remote tcp4://10.1.0.1
    }   
    on nodeb.lan {
        local /dev/gpt/hast03
        remote tcp://10.1.0.2
    }   
}

resource zhast04 {
    on nodea.lan {
        local /dev/gpt/hast04
        remote tcp4://10.1.0.1
    }   
    on nodeb.lan {
        local /dev/gpt/hast04
        remote tcp://10.1.0.2
    }   
}

Beim initialen Aufsetzen wird zuerst das HAST auf Node A erstellt, als Primary eingehängt und anschließend der ZFS Pool angelegt. Nun werden die Daten auf den Pool kopiert, erst wenn dies geschehen ist, legt man das HAST auf Node B an und hängt diese als Secondary ein. Hierdurch werden die Daten erst gegen Ende des initialen Kopierens synchronisiert, was oftmals schneller als ein paralleles Synchronisieren ist.

Der ZFS Pool ist ein möglichst simples Setup, Cache- und Logdevices werden nicht genutzt. Von Log-Devices ist in jedem Fall zu abzuraten, durch die HAST-Latenz bringen sie de facto keinen Vorteil, erhöhen aber die Wahrscheinlichkeit von Problemen bei Hardwareversagen. Cache-Devices werden wenn überhaupt außerhalb des HAST angelegt, müssen beim Schwenk aber beachtet werden. Spricht das Cache-Device des alten Masters wird entfernt und das Cache-Device des neuen Masters eingefügt.

Es ist zu empfehlen, dass zumindest ein HAST-Device Redundanz vorhanden ist. Zwar kann HAST den Ausfall einer Festplatte ausgleichen, die Daten werden dann direkt auf den Slave geschrieben, aber dies bedeutet einen massiven Performanceeinbruch. Zudem benötigt ZFS eigene Redundanz zum Self Healing.

  pool: data
 state: ONLINE
  scan: scrub repaired 0 in 0h14m with 0 errors on Fri May 27 14:26:33 2016
config:

	NAME              STATE     READ WRITE CKSUM
	data              ONLINE       0     0     0
	  raidz1-0        ONLINE       0     0     0
	    hast/zhast01  ONLINE       0     0     0
	    hast/zhast02  ONLINE       0     0     0
	    hast/zhast03  ONLINE       0     0     0
	    hast/zhast04  ONLINE       0     0     0

errors: No known data errors

Geplantes Umschalten ist nun einfach:

  1. Alle Dienste auf dem Master beenden
  2. Den ZFS Pool auf dem Master exportieren
  3. HAST auf dem Master in Init versetzen und einen Moment warten, damit alle ausstehenden Änderungen geschrieben wurden.
  4. HAST auf dem Slave in Primary versetzen
  5. Den ZFS Pool auf dem Slave importieren
  6. Den alten Master in Secondary versetzen
  7. Dienste auf dem neuen Master starten

Umschalten im Katastrophenfall läuft ähnlich ab:

  1. Sicherstellen, dass der ausgefallene Master nicht wieder zum Leben erwacht
  2. HAST auf dem Slave in Primary versetzen
  3. Den ZFS Pool per -f importieren
  4. Die Dienste auf dem neuen Master starten
  5. Ein zpool scrub ist zu empfehlen

Externe Dienste können durch einen Schwenk der DNS-Namen von dem alten Master auf den neuen Master umgeleitet werden.

freebsd/hast_best_practices.txt · Zuletzt geändert: 2016/06/05 17:05 von vater