Hochverfügbare Linux Cluster

99,999% - eine Zahl und ein Prozentzeichen. Unter Systemadministratoren hat diese Zahl eine mystische, ja geradezu ehrfürchtige Bedeutung. Der demütige Administrator hat tiefsten Respekt vor dieser Zahl, denn sie hat in seiner Branche eine ganz besondere Bedeutung.

Diese “five nines” bezeichnen nämlich die Verfügbarkeit von Services, die Uptime des Systems. Über das Jahr gerechnet bedeuten diese fünf Neunen nämlich, dass das System maximal und im allerschlimmsten Fall nicht mehr fünfeinhalb Minuten offline oder unverfügbar sein darf. Wägt man diese fünf Minuten gegen ein ganzes Jahr, hat man ungefähr eine Vorstellung davon, wie wahnsinnig wenig das ist. Jeder vollständige Reboot eines Servers dauert länger, einen Apache Neustart kriegt man kaum unter 30 Sekunden hin.

Hochverfügbarkeit ist hier das Zauberwort - denn ein hochverfügbarer Cluster, ein Verbund von Rechnern die gemeinsam die selbe Aufgabe erledigen, kann dabei helfen, diesen fünf Neunen beträchtlich näher zu kommen, zum Beispiel unter Linux mit DRBD und Heartbeat.

Motivation

Nun sind die erwähnten “fünf Neunen” nicht immer alles. Gelegentlich ist es völlig egal, ob ein System wirklich ständig erreichbar ist, oder ob es nur erreichbar ist, wenn der Anwender dessen Dienste benötigt. Dem Storageserver im Büro wird es niemand übel nehmen, wenn er sich dazu entschließt, während des nächtlichen Backups eine Stunde nicht erreichbar zu sein, denn wer benötigt die darauf gespeicherten Daten nachts um halb fünf?
Auch kann es Herr Maier durchaus vertragen, wenn “familie-maiers-privatseite.de” durch einen Hardwaredefekt mal einen Tag oder zwei nicht erreichbar ist.

Zum Problem wird die Verfügbarkeit eines Services erst, wenn geschäftskritische Anwendungen davon abhängen. Zum Beispiel im Internet. Für Firmen wie eBay und Amazon wäre es selbstredend unabdingbar die Verfügbarkeit der jeweiligen Webseiten von einem einzelnen Server oder gar einer einzelnen Festplatte abhängig zu machen. Denn hier kommen wir in der Tat in Bereiche, wo ein Ausfall des Systems wesentlich teurer ist, als die Anschaffungskosten von zusätzlicher Hardware.

Doch auch eine oder zwei Dimensionen kleiner macht es sich schnell bezahl zumindest an kritischen Punkten für Hochverfügbarkeit zu sorgen. Es mag zunächst komisch erscheinen, aber für den hauptgeschäftlichen Betreiber von Websites ist es in der Regel verkraftbar, wenn die Seite nicht erreichbar ist, niemals aber der Server, der die Werbebanner ausliefert. Die Gründe sind wirtschaftlicher Natur: der Besuch einer Seite kostet den Betreiber Geld. Je anspruchsvoller die angebotene Dienste sind, desto mehr Geld muss der Betreiber für Traffic, Hardware und Stellplatzgebühren in Rechenzentren bezahlen. Einnahmen hingegen kommen (meistens) einzig und allein dadurch zustande, dass den Besuchern Werbung eingeblendet wird.

Es ist ab einem gewissen Punkt also eine rein ökonomische Frage: Was kostet mehr, der Verdienstausfall von bloß einem Tag, durch den Streik meiner Bannerschleuder oder die Anschaffungskosten (und Folgekosten) für einen zusätzlichen Server, der im Notfall einspringt?

Redundanz

Damit ist die Kernidee von Hochverfügbarkeit bereits vorweggenommen. Man eliminiert systematisch jede potenzielle einzelne Fehlerstelle und stellt das hochverfügbare Setup einfach ein zweites Mal hin. Einfach alles, vom Switch an dem der Bannerserver im Netzwerk hängt, bis zum Server an sich. Doch anders als beim Loadbalancing wird die Last nicht zwischen diesen beiden Servern geteilt, der zweite Server macht gar nichts. Er wartet einfach nur auf seinen großen Moment, an dem der Bruder aussetzt. Dann schlägt die große Stunde des Servers, der sein ganzes Dasein damit verbrachte zu warten, den von einem Moment auf den anderen wird er die Zügel an sich reißen und den schwächelnden Kollegen ersetzen.

Aktiv/Passiv nennt man so einen Cluster und was sich zunächst nach einem verirrten Begriff aus dem BDSM-Bereich anhört, ist vielmehr das zur Anwendung kommende Prinzip eines HA-Clusters. Ein Server tut anstandslos seinen Dienst, der zweite wartet einfach darauf, dass auf dem anderen Probleme auftauchen. Passiert das nie, auch gut. Doch passiert es, stellt sich ein hochverfügbares Setup vollautomatisch auf Passiv/Aktiv um, wechselt also die Rollen. Korrekter wäre für die beiden Server im BDSM-Bereich also wohl “Switcher”, aber lassen wir das …

Sinnvoll ist eine derartige Lösung natürlich nur, wenn es eben keinen einzelnen Fehlerpunkt ist, einen “Single Point of Failure”. Was bringt es nämlich, einen hochverfügbaren Aktiv/Passiv Cluster in das Rechenzentrum zu stellen, wenn dieser dann am selben Stromkreis, am selben Switch, an der selben Datenbank hängt wie der andere. Erscheint logisch, wenn man schon zwei redundante Server aufbaut, darf man nicht an den falschen Enden sparen.

In der Theorie ist ein HA-Cluster auch gar nicht kompliziert, problematisch wird das erst mit konkreten Anwendunsszenarien, spätestens wenn es darum geht, auf dem passiven System jederzeit den aktuellen Datenbestand verfügbar zu haben. Denn allein mit der Hardware ist es schließlich nicht getan, auch die darauf laufende Software muss transparent identisch sein. Das erfordert zum Beispiel, dass Verzeichnisse und Datenbanken, die auf Aktiv/Passiv Clustern laufen abgeglichen werden oder aber an anderer Stelle abgelegt sind. Im Beispiel vom Bannerserver müssen zumindest die Werbebanner abgeglichen werden, denn ein erreichbarer Bannerserver, der die Grafiken für aktuell geschaltete Kampagnen nicht vorrätig hat, ist natürlich ebenso wenig tolerierbar.

Hardware

In der Praxis ist es für Cluster eine komplexe Angelegenheit festzustellen wo ein Defekt zu lokalisieren ist. Für jeden Node im Cluster ist es ein heuristisches Verfahren herauszufinden, wer kaputt ging, der Node oder sein Partner oder ein externer Faktor (Netzwerk). Daher versucht man sich bei der Hardware möglichst abzusichern um dort Defekte von vornherein auszuschließen. Festplatten im RAID sind Pflicht, ebenso redundante Netzteile. Das ganze natürlich zweimal oder öfter, über “Single Point of Failures” hatten wir schon gesprochen.

Ebenso wichtig ist eine dedizierte Verbindung zwischen den Nodes vom Cluster, zwei Nodes kann man zu diesem Zweck am einfachsten seriell oder über GBit-LAN verbinden. Unabhängig und zusätzlich von jeder Anbindung nach außen versteht sich.

Ein einfacher HA-Cluster sähe also wie folgt aus:


Der passive Server zwischen den beiden muss nicht unbedingt über die gleichen Leistungsdaten verfügen, wie jener, der im Regelbetrieb aktiv ist und kann durchaus schwächer ausgestattet sein. Kann der wartende Server im Ernstfall die Last nicht abfangen, ist das Konzept in sich allerdings auch sinnlos, insofern benötigt man schon ein bisschen mehr als eine alte übrig gebliebene Kiste aus dem letzten Krieg.

Im Zuge des Virtualisierungswahns ist es auch möglich, einen oder beide Nodes des Clusters auf eine virtuelle Maschine, zum Beispiel in eine Xen-Instanz zu verlegen. Selbstverständlich nicht beide auf die selbe physikalische Maschine …

Einen Cluster aufsetzen

Mit richtigen Betriebssystemen wie Linux ist es kein Problem einen derartigen Cluster aufzusetzen. Es ist sogar erstaunlich einfach und mit wenigen Handgriffen ist das getan. Beschrieben wird ein Aktiv/Passiv Cluster unter Linux mit der freien Software DRBD und Heartbeat. Als hoch verfügbare Dienst wird ein Banner- und Trackingserver eingerichtet, auf dem Apache und eine lokale mySQL-Datenbank läuft.

Vorbereitungen

Benötigt werden zwei Server mit - wichtig - der selben Architektur. Es ist nicht möglich (soweit es diese Anleitung betrifft) die beiden Cluster Nodes unter verschiedenen Architekturen zu betreiben, wohl aber unter verschiedenen Linux Distributionen, wobei der Sinn fraglich bleibt.

Mein Setup besteht aus zwei identischen 1 HE-Servern (Dual AMD Opteron 248, 8 GB RAM mit drei SATA-Festplatten). Beide Server verfügen über zwei Netzwerk-Interfaces. Auf der ersten Festplatte wird das Betriebssystem installiert, ich verwende Debian Etch, diese Anleitung ist so jedoch genauso auf Ubuntu Dapper LTS übertragbar. In eth0, dem ersten Netzwerk-Interface konfiguriere ich die externe IP. Auf eth1 verbinde ich die beiden Server über ein Crossover-Kabel. Die beiden anderen Platten bilden ein Software-RAID 1. Sowohl unter Debian, als auch unter Ubuntu ist das bereits bei der Installation auswählbar. Wichtig ist: dieses RAID wird aber nicht gemountet und auch kein Dateisystem darauf abgelegt - alle Daten darauf gingen später durch die Einrichtung verloren!

Kenndaten:

  • Server 1: “srv1″, eth0: 168.192.0.2, eth1: 192.168.0.1, / auf /dev/sda1, RAID 1 als /dev/md0 eingerichtet aber unbenutzt
  • Server 2: “srv2″, eth0: 168.192.0.3, eth1: 192.168.0.2, / auf /dev/sda1, RAID 1 als /dev/md0 eingerichtet aber unbenutzt

Weiter gibt es eine weitere HA-IP-Adresse. Wozu diese benötigt ist, werde ich später erörtern, an der Stelle sei nur darauf hingewiesen, dass diese zwingend nötig ist und im selben Netz wie die externen Adressen der beiden Cluster Nodes liegen muss. Ich wähle daher “168.192.0.4″.

DRBD

Bei einem Aktiv/Passiv Cluster besteht die Notwendigkeit, dass auf beiden Nodes der selbe Datenbestand gehalten wird. Es müssen auf beiden Systemen absolut die selben Daten vorliegen. Das bedeutet für unseren Cluster das sowohl das Webverzeichnis in dem die Banner liegen werden, als auch das mySQL-Datenverzeichnis zu jedem Zeitpunkt auf beiden Servern identisch ist. Es reicht nicht aus, die Daten zum Beispiel über einen Cronjob alle 5 Minuten zu synchronisieren (bei den mySQL-Daten wäre das sowieso nicht möglich, ohne die Datenbank herunterzufahren).

Hier bietet sich DRBD geradezu an. DRBD spiegelt Schreibvorgänge und damit jede Änderung der Daten blockweise über das Netzwerk auf einen zweiten Server. Werden Daten geschrieben, werden die ganz regulär auf die lokale Festplatte übertragen, parallel dazu aber auch über das Netzwerk einem beliebigen zweiten Rechner im Netz übermittelt, das als passiver Teil die Änderungen einfach übernimmt. DRBD ist aber kein verteiltes (Netzwerk-) Dateisystem, es ist damit nicht möglich etwa auf beiden Servern zugleich Daten zu schreiben, der passive Server kann die Daten noch nicht einmal lesen!

Es ist damit eine reine Clusterlösung und macht Datenreplikation, kein gemeinsamer Austausch und Nutzung von Daten (”Share Nothing Policy”). Die Installation erfolgt erfreulich umkompliziert, ich verwende drbd-0.7:


foo@srv1:~$ sudo su
root@srv1:~# uname -r
2.6.18-6-amd64
root@srv1:~# apt-get install linux-headers-2.6.18-4-amd64 drbd0.7-module-source drbd0.7-utils
root@srv1:~# module-assistant auto-install drbd0.7-module-source
root@srv1:~# modprobe drbd

Dies baut das drbd Kernelmodul und lädt es in den Kernel. Dieser Vorgang ist auf beiden Servern identisch durchzuführen. Spätestens ab diesem Zeitpunkt jetzt muss das Crossoverkabel zwischen srv1 und srv2 vorhanden und die lokalen IPs hochgefahren sein. Nun muss das DRBD nämlich konfiguriert werden. Dazu verwende ich das bislang unbenutzte RAID 1 unter “/dev/md0″. Die Konfiguration von DRBD erfolgt in “/etc/drbd.conf” und ist weitgehend selbsterklärend. Doku lesen ist trotzdem erlaubt. Ich konfiguriere einfach eine verteiltes Dateisystem, bei DRBD “Resource” genannt über zwei Nodes auf die internen IP-Adressen von srv1 und srv2. Die Optionen in startup {} weisen DRBD an, nach 120 Sekunden (vergeblichen) wartens dennoch hochzufahren. Alles andere würde, falls einer der beiden Nodes bei einem (Re-)Boot, auf eine Benutzereingabe in der Boot-Shell warten. Das ist auf Servern natürlich dumm …

Es sei mir noch der Hinweis erlaubt dass die “on srv1 {}” Bereiche tatsächlich die beiden Hostnamen vom Server sind. Diese müssen mit den tatsächlichen übereinstimmen. Auch diese Konfiguration ist auf beiden DRBD-Nodes identisch.

/etc/drbd.conf:

resource r0 {
    syncer { rate 600M; }
    startup {
                degr-wfc-timeout 120;
                wfc-timeout     120;
        }
    protocol               C;

  on srv1 {
    device      /dev/drbd0;
    disk        /dev/md0;
    address     192.168.0.2:7789;
    meta-disk   internal;
  }

  on srv2 {
    device      /dev/drbd0;
    disk        /dev/md0;
    address     192.168.0.3:7789;
    meta-disk   internal;
  }
}

Danach kann und sollte das DRBD auf beiden Servern neugestartet werden:


root@srv1:~# /etc/init.d/drbd restart
root@srv1:~# cat /proc/drbd
version: 0.7.15 (api:77/proto:74)
SVN Revision: 2020 build by root@srv1, 2008-02-22 22:33:02
0: cs:Connected st:Secondary/Secondary ld:Inconsistent
ns:0 nr:0 dw:0 dr:0 al:0 bm:16 lo:0 pe:0 ua:0 ap:0
1: cs:Unconfigured

So, oder so ähnlich sollte auf beiden Servern die Ausgabe aussehen. Der wichtige Punkt an dieser Ausgabe ist “cs:Connected” und “st:Secondary/Secondary”. Diese besagen zweierlei, nämlich dass sich die beiden Server einerseits gefunden haben (”Connected”) und dass beide im Status passiv sind. Das ist für den ersten Start gut und richtig so. Es bleibt dem Administrator überlassen einen der beiden Nodes zum Hauptserver (im DRBD-Jargon “Primary”) zu ernennen, den anderen zum passiven Server, der Änderungen nur übernimmt (”Secondary”). Dies geschieht mittels


root@srv1:~# drbdadm -- --do-what-I-say primary all

Wichtig ist an der Stelle, dass dieser Befehl nur auf einem der beiden Nodes durchgeführt werden darf. Ein Blick in /proc/drbd sollte nun zeigen, dass der Node, auf dem dieser Befehl ausgeführt wurde nun der primäre Node ist (”st:Primary/Secondary”), die Ausgabe des zweiten Nodes hingegen sekundär (”st:Secondary/Primary”).

Auf dem Haupt-Node kann nun das Dateisystem formatiert und gemountet werden:


root@srv1:~# mkfs.ext3 /dev/drbd0
root@srv1:~# mkdir /data
root@srv1:~# mount /dev/drbd0 /data

Ein neuerlicher Blick in /proc/drbd sollte nun zeigen, dass die Daten auf beiden Nodes erstmalig synchronisiert werden bzw. bereits wurden. Je nach Größe der Partition kann das eine ganze Weile dauern. Das Ende dieses Vorgangs muss nicht abgewartet werden, schadet aber auch nicht, zumal das System während dieser Zeit sehr langsam sein wird. Ist der DRBD synchron wird wird das ebenso in /proc angezeigt:


root@srv1:~# cat /proc/drbd
version: 0.7.15 (api:77/proto:74)
SVN Revision: 2020 build by root@srv1, 2008-02-22 22:33:02
0: cs:Connected st:Primary/Secondary ld:Consistent
ns:105641581 nr:929296 dw:106723605 dr:10369734 al:790836 bm:464 lo:0 pe:0 ua:0 ap:0

Achtung, /dev/drbd0 darf nicht in /etc/fstab eingetragen werden. Das mounten und umounten wird später Heartbeat übernehmen, genauso die gesamte Verwaltung (einen Node aktiv setzen, einen Wechsel auf den passiven Node veranlassen …). Daher muss der manuell gemountete DRBD-Array später wieder aus dem Dateisystem ausgehängt werden.

Auf srv2 wird vorerst nur der Mountpunkt erzeugt:


root@srv2:~# mkdir /data

Apache und mySQL

Der Cluster soll die Banner- und Trackingserver einer Website werden. Dazu wird ein Webserver mit PHP-Unterstützung und eine zugehörige Datenbank benötigt. Beides gehört zum populären und weit verbreiteten LAMP-Stack und macht entsprechend wenig Probleme. Auch hier sind sämtliche zu installierende Pakete und Konfigurationsänderungen auf beiden Servern vorzunehmen.

Auch hier sind alle Pakete sowohl in Debian als auch Ubuntu vorhanden. Daher ist die Installation unkompliziert:

root@srv1:~# apt-get install apache2 libapache2-mod-php5 mysql-server-5.0 mysql-client

Standardmäßig liegen die Datenverzeichnisse unter Debian für Webserver und Datenbank in “/var/www” und “/var/lib/mysql”. Das ist für meine Zwecke allerdings unpassend, weil gemeinsam genutzte Daten unterhalb vom verteilten Dateisystem in “/data” abgelegt werden. Daher nehme ich folgende Änderungen vor:

In /etc/mysql/my.cnf:

[..]
datadir         = /data/mysql
[..]
#Binlogs deaktivieren (werden nicht benötigt)
#log_bin                 = /var/log/mysql/mysql-bin.log
#expire_logs_days        = 10
#max_binlog_size         = 100M

Ähnlich verfahre ich auch mit Apache und lege einen neuen namensbasierten VirtualHost an (/etc/apache2/sites-available/example.com):

NameVirtualHost *
<VirtualHost *>
        ServerName example.com
        DocumentRoot /data/www/example.com

        <Directory /data/www/example.com>
                Options -Indexes
                AllowOverride All
        </Directory>

        CustomLog /dev/null combined
</VirtualHost>

Natürlich kann und darf sowohl Apache als auch mySQL noch weiter konfiguriert und optimiert werden. Wie zuvor DRBD wird auch diese Daemons später heartbeat verwalten und den Start und Stop von mySQL und Apache veranlassen. Deshalb müssen diese beiden Daemons aus dem Standard Runlevel entfernt werden (2 unter Debian und Ubuntu). Außerdem sind noch einige kleinere Aufräumarbeiten nötig. Weiterhin kopiere ich noch die Zugangsdaten für den Debian mySQL-Benutzer von srv1 auf srv2, damit das Startscript beim hochfahren von mySQL keine Fehler wirft:

Auf srv1 und srv2:

root@srv1:~# update-rc.d -f mysql remove
root@srv1:~# update-rc.d -f apache2 remove
root@srv1:~# a2dissite 000-default
root@srv1:~# a2ensite example.com
root@srv1:~# /etc/init.d/mysql stop
root@srv1:~# /etc/init.d/apache2 stop
root@srv1:~# rm -rf /var/www

Nur auf srv1:

root@srv1:~# mkdir -p /data/www/example.com
root@srv1:~# mv /var/lib/mysql /data
root@srv1:~# chown mysql:mysql /data/mysql
root@srv1:~# chown www-data:www-data /data/www/example.com
root@srv1:~# umount /data
root@srv1:~# drbdadm secondary all

Nur auf srv2:

root@srv2:~# rm -rf /var/lib/mysql
root@srv2:~# scp root@srv1:/etc/mysql/debian.cnf /etc/mysql/debian.cnf

Damit sind die beiden hochverfügbaren Web- und DB-Diense bereit, von heartbeat kontrolliert zu werden. Sämtliche relevanten Daten werden unterhalb von /data erwartet und können dort später auch abgelegt werden. Der aufwändigste Teil ist damit erledigt, was noch bleibt ist heartbeat, der auf dem Cluster die Kontrolle und Steuerung von Diensten erledigen wird. Damit bildet es das Herzstück vom Cluster, denn es fügt alle Komponenten zusammen.

Heartbeat

Eigentlich könnte man es auch dabei belassen, denn die Grundvoraussetzungen sind erfüllt: Redundante Hardware liegt, ein gemeinsamer Bereich von geteilten Daten und jeweils gleich konfigurierte Webserver und Datenbanken. Fällt ein Server aus, könnte man innerhalb kurzer Zeit manuell auf die bereitstehende zweite Hardware wechseln. Hochverfügbarkeitsanforderungen genügt das natürlich nicht und den “fünf Neunen” sowieso nicht. Eine manuelle Übergabe auf den passiven Server, wird kaum in fünf Minuten zu schaffen sein.

Besser ist es eine Softwaresteuerung die Kontrolle zu übergeben, die anstatt manueller Interaktion selbständig agiert und vor allem reagiert. Hier kommt heartbeat ins Spiel, der folgende Aufgaben übernehmen wird:

  • Überwachung/Monitoring vom eigenen Status.
  • Überwachung/Monitoring vom Status des anderen Node.
  • Überwachung der Netzwerkverfügbarkeit.
  • Teilen bzw. gemeinsames verwalten einer HA-IP-Adresse.
  • Ein- und Aushängen von “/data” auf dem aktiven Node.
  • Starten und stoppen von mySQL und Apache.
  • Übergabe bzw. Übernahme der Dienste nach Bedarf an den passiven Node

Im Groben dürften die Aufgaben von heartbeat damit klar sein. Erklärung bedarf vermutlich noch die HA-IP-Adresse. Es kann verständlicherweise nicht sein, dass man sich bei einem hochverfügbaren Dienst auf eine IP-Adresse festlegt. Die Domain, die der Cluster bereitstellen soll, “example.com” darf natürlich weder auf srv1 (168.192.0.2) noch auf srv2 (168.192.0.3) auflösen. Beide IPs sind maschinengebunden. Fällt srv1 aus, kann srv2 vielleicht einspringen. Das nützt aber nichts, wenn die Web-Browser “example.com” weiterhin unter 168.192.0.2 vermuten.
Vielmehr benutze ich hier die dritte IP, die ich eingangs erwähnte 168.192.0.4. Diese “gehört” keinem der beiden Server, sie wird vielmehr zwischen diesen beiden geteilt. Nur der jeweils aktive Node hat diese IP-Adresse hochgefahren, der Apache Webserver wird unter dieser zusätzlichen IP-Adresse Anfragen entgegen nehmen. Soll eine Übergabe an den passiven Server erfolgen, fährt der aktive diese IP-Adresse sofort herunter und “übergibt” sie. Das funktioniert (in der Regel) so gut, dass dieser Umzug im Bruchteil einer Sekunde abgeschlossen werden kann, ohne eine nennenswerte Anzahl an Paketen zu verlieren. Pingt man zum Beispiel diese HA-IP während eines Takeovers an, geht in der Regel nicht mehr als ein Paket verloren.

Ich mag an der Stelle gar nicht mit Details langweilen, es ist allerdings klar, dass diese Art und Weise eine IP zu teilen, so schnell nur funktionieren kann, wenn man sich Methoden bedient, die technisch unter IP-Spoofing fallen. Die Uplink-Switches im Netz müssen also in der Regel mit einem manipulierten ARP-Paket überlistet werden, damit der Umzug so vonstatten gehen kann. Auch das erledigt heartbeat.

Auch hier wird es bereits alles nötige von Debian mitgeliefert und mit der Installation des Paketes auf beiden Servern ist die Installation erledigt. Auch die Konfigurationsdateien unterschieden sich nicht auf beiden Nodes:


root@srv1:~# apt-get install heartbeat

Die Konfiguration von heartbeat gestaltet sich ebensowenig kompliziert. heartbeat kennt drei Konfigurationsdateien, alle drei müssen von Hand in /etc/ha.d/ angelegt werden:

  • authkeys: Schlüssel zur Authentifizierung
  • ha.cf: heartbeat-Konfiguration (Daemon)
  • haresources: heartbeat-Konfiguration (Verteilte Ressourcen)

Um gegen Angriffe aus dem lokalen Netz abgesichert zu sein, authentifiziert heartbeat die Kommunikation zwischen den Servern im Cluster. Das erscheint logisch, werden darüber doch Metabefehle gestreut, die auf den Nodes veranlassen, Daemons zu starten und stoppen oder eventuell auch einen Reboot des Systems zu veranlassen. Die Konfiguration hierfür ist einfach:

/etc/ha.d/authkeys:

auth 1
1 sha1 kennwort


root@srv1:~# chmod 600 /etc/ha.d/authkeys

Der Daemon selbst wird in /etc/ha.d/ha.cf konfiguriert:


debugfile /var/log/ha-debug
logfile /var/log/ha-log
keepalive 2
deadtime 4
bcast eth1
node srv1 srv2
auto_failback on
ping 168.192.0.1
respawn hacluster /usr/lib/heartbeat/ipfail

Die Konfiguration ist weitgehend selbsterklärend und konfiguriert einen Cluster mit zwei Nodes (”node srv1 srv2). Auch hier ist unbedingt der korrekte Hostname der Server anzugeben. Die Kommunikation erfolgt über UDP-Broardcasts im internen Netz, das auf eth1 konfiguriert ist und bereits für DRBD verwendet wird. Die Direktive “auto_failback on” veranlasst heartbeat Ressourcen immer auf den primären Träger zu übertragen, wenn dieser (wieder) verfügbar ist. Die Verfügbarkeit des Partners ermittelt heartbeat über “keepalive” und “deadtime”. In diesem Fall schickt heartbeat alle 2 Sekunden ein Paket aus um den Status des jeweils anderen Nodes zu überprüfen, hat dieser nach 4 Sekunden noch nicht geantwortet wird er für tot erklärt und gegebenenfalls ein Takeover veranlasst.

“ping 168.192.0.1″ dient dazu den eigenen Status zu ermitteln. Dazu pingt heartbeat beständig die angegebene IP-Adresse an und stellt so fest, ob heartbeat selbst offline ist. Dazu kann jede beliebige erreichbare IP-Adresse verwendet werden (168.192.0.2 bzw. 168.192.0.3 als IPs von den Cluster Nodes ist allerdings keine gute Idee …). Am meisten Sinn macht es vermutlich hier die IP-Adresse vom Gateway der beiden Rechner anzugeben, also den Uplink-Router. In meinem Beispiel ist das 168.192.0.1.

Eine vollständige Liste der verfügbaren Direktiven ist auf der Linux-HA Website dokumentiert.

Kernstück des Clusters ist die Konfigurationsdatei /etc/ha.d/haresources. Darin wird festgelegt, welche Dienste, Services und IP-Adressen hochverfügbar sind, also auf beiden Servern verfügbar sein sollen. heartbeat wird auf dem aktiven Node diese schließlich selbständig starten.

Die Syntax der Datei ist einfach. “name-des-hauptnodes ressource”, wobei name-des-hauptnodes der Hostname des primären Trägers einer Ressource ist (der aktive Server). Ich möchte eine IP-Adresse hochverfügbar haben, eine DRBD-Partition mit Daten und die beiden Daemons apache und mysql. Entsprechend sieht haresources aus:


srv1 168.192.0.4
srv1 drbddisk::r0 Filesystem::/dev/drbd0::/data::ext3
srv1 mysql apache2

Beim Hochfahren des Clusters führt heartbeat so autonom und selbständig folgende Befehle durch:


# ifconfig eth0:0 168.192.0.4 up
# mount -t ext3 /dev/drbd0 /data
# /etc/init.d/mysql start
# /etc/init.d/apache2 start

Dabei erwartet heartbeat, dass keine dieser Ressourcen bereits an einen Node gebunden ist. Das heißt der Administrator darf keinesfalls DRBD selbst mounten, oder einen der beiden Dienste hochstarten. Deswegen war es auch wichtig, dass diese Dienste auch aus dem Boot-Runlevel entfernt wurden.

Nachdem diese drei Konfigurationsdateien angelegt sind, kann heartbeat gestartet werden. Dazu auf beiden Servern einfach den Daemon starten:


root@srv1:~# /etc/init.d/heartbeat restart

Die Log-Datei und insbesondere das Debug-Log geben Aufschluss ob alles geklappt hat, Debug-Log zusätzlich was heartbeat genau tut:

srv1 (Aktiv):

heartbeat: 2008/02/28_22:30:07 info: heartbeat: version 1.2.4
heartbeat: 2008/02/28_22:30:07 info: Heartbeat generation: 16
heartbeat: 2008/02/28_22:30:07 info: UDP Broadcast heartbeat started on port 694 (694) interface eth1
[..]
heartbeat: 2008/02/28_22:30:08 info: Local status now set to: 'up'
[..]
heartbeat: 2008/02/28_22:30:08 info: Link srv1:eth1 up.
[..]
heartbeat: 2008/02/28_22:30:08 info: Link 168.192.0.1:168.192.0.1 up.
heartbeat: 2008/02/28_22:30:08 info: Status update for node 168.192.0.1: status ping
heartbeat: 2008/02/28_22:30:09 info: Link srv2:eth1 up.
heartbeat: 2008/02/28_22:30:09 info: Status update for node srv2: status active
heartbeat: 2008/02/28_22:30:09 info: Local status now set to: 'active'
[..]
heartbeat: 2008/02/28_22:30:24 info: Acquiring resource group: srv1 168.192.0.4
heartbeat: 2008/02/28_22:30:24 info: Running /etc/ha.d/resource.d/IPaddr 168.192.0.4 start
heartbeat: 2008/02/28_22:30:24 info: /sbin/ifconfig eth0:0 168.192.0.4 netmask 255.255.255.0 broadcast 168.192.0.255
heartbeat: 2008/02/28_22:30:24 info: Sending Gratuitous Arp for 168.192.0.4 on eth0:0 [eth0]
heartbeat: 2008/02/28_22:30:24 /usr/lib/heartbeat/send_arp -i 1010 -r 5 -p /var/lib/heartbeat/rsctmp/send_arp/send_arp-168.192.0.4 eth0 168.192.0.4 auto 168.192.0.4 ffffffffffff
heartbeat: 2008/02/28_22:30:24 info: Acquiring resource group: srv1 drbddisk::r0 Files
ystem::/dev/drbd0::/data::ext3 mysql apache2
heartbeat: 2008/02/28_22:30:24 info: Running /etc/ha.d/resource.d/drbddisk r0 start
heartbeat: 2008/02/28_22:30:24 info: Running /etc/ha.d/resource.d/Filesystem /dev/drbd0 /data ext3 start
heartbeat: 2008/02/28_22:30:25 info: Running /etc/init.d/mysql start
heartbeat: 2008/02/28_22:30:26 info: Running /etc/init.d/apache2 start

srv2 (Passiv):


heartbeat: 2008/02/28_22:24:40 info: Configuration validated. Starting heartbeat 1.2.4
heartbeat: 2008/02/28_22:24:40 info: heartbeat: version 1.2.4
heartbeat: 2008/02/28_22:24:40 info: Heartbeat generation: 12
[..]
heartbeat: 2008/02/28_22:24:40 info: UDP Broadcast heartbeat started on port 694 (694) interface eth1
heartbeat: 2008/02/28_22:24:41 info: Link 168.192.0.1:168.192.0.1 up.
heartbeat: 2008/02/28_22:24:41 info: Status update for node 168.192.0.1: status ping
heartbeat: 2008/02/28_22:24:41 info: Link srv1:eth1 up.
heartbeat: 2008/02/28_22:24:41 info: Status update for node srv1: status active
heartbeat: 2008/02/28_22:24:41 info: Local status now set to: 'active'
heartbeat: 2008/02/28_22:24:41 info: Starting child client "/usr/lib/heartbeat/ipfail" (105,110)
heartbeat: 2008/02/28_22:24:41 info: Starting "/usr/lib/heartbeat/ipfail" as uid 105 gid 110 (pi
d 26229)
heartbeat: 2008/02/28_22:24:41 info: remote resource transition completed.

Verifiziert werden kann das ganz einfach, indem man die Ressourcen überprüft, angefangen bei der HA-IP-Adresse:


root@srv1:/etc/ha.d# ifconfig
eth0 Link encap:Ethernet HWaddr 00:00:03:14:15:92
inet addr:168.192.0.2 Bcast:168.192.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15676061539 errors:0 dropped:0 overruns:0 frame:0
TX packets:13665848906 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2505960787305 (2.2 TiB) TX bytes:2254104514033 (2.0 TiB)
Interrupt:185

eth0:0 Link encap:Ethernet HWaddr 00:00:03:14:15:92
inet addr:168.192.0.4 Bcast:168.192.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
Interrupt:185
[..]

Auf dem passiven Node hingegen darf die HA-IP natürlich nicht existieren:


root@srv2:/etc/ha.d# ifconfig
eth0 Link encap:Ethernet HWaddr 00:00:23:42:03:FB
inet addr:168.192.0.3 Bcast:168.192.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15676061539 errors:0 dropped:0 overruns:0 frame:0
TX packets:13665848906 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1133145993 (1.0 GiB) TX bytes:859118182 (819.3 MiB)
Interrupt:185
[..]

Auf dem primären Node muss zudem der DRBD gemountet sein:


root@srv1:/etc/ha.d# mount | grep "drbd"
/dev/drbd0 on /data type ext3 (rw)
root@srv2:/etc/ha.d# grep "0:" /proc/drbd
0: cs:Connected st:Primary/Secondary ld:Consistent

während es auf dem passiven Node natürlich umgekehrt sein muss:


root@srv2:/etc/ha.d# mount | grep "drbd"
root@srv2/etc/ha.d# grep "0:" /proc/drbd
0: cs:Connected st:Secondary/Primary ld:Consistent

Nach Bedarf kann man auch von Hand einen Takeover bzw. die Freigabe von Ressourcen erzwingen. Das kann sinnvoll sein, wenn man Wartungsarbeiten (Updates, Backups …) auf den beiden Nodes zeitversetzt macht. Dazu benutzt man die Tools “hb_takeover” bzw. “hb_standby” die jeweils für den lokalen Noden gelten. “hb_takeover” auf srv2 veranlasst also ein Takeover auf srv2. Bei Debian und Ubuntu finden sich diese Programme in “/usr/lib/heartbeat/” und damit vermutlich nicht im $PATH, müssen also mit vollem Pfad ausgeführt werden.

Ob ein ungeplanter Takeover korrekt vonstatten geht, kann ebenso einfach überprüft werden, einfach mal den Stecker ziehen, heartbeat übernimmt den Rest.

Ob sich damit die “fünf Neunen” Verfügbarkeit erreichen lassen, ist natürlich noch nicht gewiss. Dennoch ist man dem Ziel schon beträchtlich näher gekommen. Mit reinen Open Source Tools.

Kategorien

Eingeordnet unter: , und

Verwandte Artikel

6 Antworten auf »Hochverfügbare Linux Cluster«

  1. Ui, dafür interessiere ich mich auch seit einiger Zeit, habe es mir aber noch nicht genauer angeschaut.
    Sieht gut aus, Dein Post. Muss ihn mal in Ruhe bei einem Kaffee lesen.

    jesse - 29. Februar 2008 um 14:10

  2. Auch wenn du bekanntlich nicht bloggst: Deine Artikel sind interessant, verständlich geschrieben und man merkt, dass du weißt, wovon du schreibst. Vor allem hast du etwas zu sagen und das ist bei (fast) 99,999% der Blogs nicht der Fall.
    Insofern: Mach weiter so!

    Gruß,
    T-4

    Tsafor - 1. März 2008 um 16:11

  3. Hi onkelchen!
    Habe mal ne Verstaendnisfrage: was wenn die Heartbeat-Verbindung zwischen den Servern abreisst?
    Die beiden server laufen ja noch und haben beide Verbindung nach aussen. Auf dem passiven Server scheitert das heartbeat, es wird in den aktiven Zustand versetzt, der aktive laeuft aber noch -> Konflikt. Oder?
    Gibts da Mechanismen um das irgendwie zu verhindern?
    das erste was einfaellt waere ein redundanter heartbeat-link, dieser muss aber in irgendeiner Form auch ueberwacht werden….

    1nk - 2. März 2008 um 21:29

  4. Du hast recht. Wenn du dich nicht auf die Netzwerkverbindung verlassen willst, kannst du die Kommunikation zwischen den beiden Servern auch über ein serielles Kabel machen. Das wird je nach Setup sogar empfohlen.
    Das geht auch zusätzlich zur internen Netzverbindung.

    Alternativ kannst du das Problem ausschließen, indem du zusätzlich zum dedizierten Broadcast-Interface auch das externe nimmst. Ist der Node darüber noch online - und davon geht dein Szenario aus - ist er auch da erreichbar. Dazu einfach

    bcast eth0 eth1

    in die ha.cf schreiben. Das kann aber Probleme geben, wenn der externe Link gut ausgelastet ist, insbesondere mit sehr kurzen Reaktionszeiten (deadtime/keepalive).

    Arno - 3. März 2008 um 15:22

  5. Danke für die SUPER Anleitung, habe soeben mein Fallback-baby am laufen.

    Achtung unter Ubuntu-Server 6.06 muss /bin/sh auf /bin/bash verlinkt sein, ansonsten kann der DRBD nicht mounten :-)

    sudo rm /bin/sh
    sudo ln -s /bin/bash /bin/sh

    ansonsten einwandfrei :-)

    Thomas - 1. April 2008 um 15:31

  6. […] Generell skalierbar aufsetzen: http://burnachurch.com/69/hochverfuegbare-linux-cluster/ […]

    Scheiss Skalierbarkeit - Teil 2 « devswi - weiter gehts - 19. Juli 2008 um 17:49

Einen Kommentar schreiben