Aus Linux-Magazin 05/2007

Load-Balancing- und High-Availability-Cluster mit IPtables

peps, Photocase.com

Wichtige Applikationen müssen trotz hängender Hardware und abstürzender Software verfügbar bleiben. Mit redundanten Servern gelingt dies: IPtables lässt sie im Cluster antreten und verteilt die Arbeit. Beim Ausfall eines Knotens schultert ein anderer dessen Last.

Egal ob Leben oder IT: Muss eine Arbeit verrichtet werden, selbst wenn der Arbeiter wegen Grippe ausfällt, geht das nur mit Ersatzkräften. Hier wie dort stellt sich die Frage, ob der Ersatzmann nur im Notfall einspringt oder ob er schon mitwerkeln soll, während der Kollege noch gesund ist. In die Informationstechnik übertragen, steht entweder neben dem Produktivsystem ein Standby-Computer, der erst im Ernstfall einspringt, oder ein Load-Balancing-Cluster verteilt die Last laufend auf mehrere Maschinen. Letzteres gibt es zentralistisch gesteuert oder kollektiv ausgehandelt.

Bei dem Gespann aus Produktivsystem und Standby-Maschine wacht eine Cluster-Software wie Heartbeat über das erste System und schaltet bei Anzeichen eines Problems automatisch auf die zweite Maschine um. Das geschieht meist durch Übernahme einer gemeinsamen MAC-Adresse. Im Netzwerk ist dieser Ansatz durch die Protokolle HSRP (Hot Standby Router Protocol), VRRP (Virtual Router Redundancy Protocol) oder CARP (Common Address Redundancy Protocol) realisiert. Vom Linux-HA-Projekt [1] stammt die bekannteste Umsetzung für HA-Server-Cluster.

Beim Load Balancing verteilt meist eine zentrale Instanz die Arbeit auf die Koten [2]. Sind genügend Reserven vorhanden, kann ein Knoten aus dem Verbund austreten. Um keinen Single Point of Failure zu erzeugen, empfiehlt es sich, die Zentralinstanz wiederum über Heartbeat hochverfügbar auszulegen.

Dezentral

Wer die zentrale Load-Balancing-Instanz gänzlich scheut, greift zum Beispiel zum »CLUSTERIP«-Target von IPtables. Es ist bereits im offiziellen Netfilter-Code enthalten, arbeitet aber noch nicht ganz stabil. Dennoch überzeugt die Technik: Bei Cluster-IP berechnet jeder Knoten selbst anhand eines Hash-Algorithmus, ob er für eine Verbindung zuständig ist.

Kontrolle über das System hat der Administrator, indem er Zuständigkeiten dem Knoten online über »/proc/net/ipt_CLUSTERIP« mitteilt. So können Mensch oder Skript dynamisch in die Lastverteilung oder -übernahme eingreifen. Diese Methode ist schon länger in den Produkten der Firma Stonesoft [3] realisiert und funktioniert dort hervorragend.

Beispielcluster

Der Cluster in Abbildung 1 besteht aus zwei Knoten. Jeder besitzt ein Interface im LAN (»eth0«) und ein weiteres im Managementnetz (»eth1«), über das sich die Knoten gegenseitig prüfen und steuern. Besteht der Cluster nur aus zwei Knoten, genügt ein Crossover-Kabel als Ersatz für den Management-Switch.

Abbildung 1: Die LAN-Interfaces beider Cluster-Knoten sind zu einem virtuellen Interface mit einheitlicher IP- und MAC-Adresse zusammengefasst. Daneben gibt es ein Management-Netz.

Abbildung 1: Die LAN-Interfaces beider Cluster-Knoten sind zu einem virtuellen Interface mit einheitlicher IP- und MAC-Adresse zusammengefasst. Daneben gibt es ein Management-Netz.

Im LAN erhält jedes Interface zusätzlich eine gemeinsame virtuelle Cluster-Adresse, über die Clients später den gesamten Cluster ansprechen. Jeder Knoten ermittelt selber, ob er zuständig ist – dazu muss ihn das Paket aber schon erreicht haben. Der Cluster erhält daher eine gemeinsame IP-Adresse sowie eine gemeinsame MAC-Adresse, die auf jedem Knoten gleich lauten. Das klappt nur mit Multicast-MAC-Adressen, erkennbar am gesetzten niederwertigen Bit im höchstwertigen Byte. Die Multicast-Adresse verhindert Adressenkonflikte.

Einen Haken hat dies allerdings: RFC 1812 [4] bestimmt, dass ein Router keinem ARP-Reply (Address Resolution Protocol) vertrauen darf, der einer IP-Adresse eine Multicast- oder Broadcast-MAC zuordnet. Bei Routern, die sich sklavisch an das RFC halten, muss der Admin diese Multicast-MAC statisch in die ARP-Tabelle eintragen.

Switches geben empfangene Multicast-Pakete normalerweise an allen Interfaces aus. Das kann bei hochverfügbaren Architekturen mit HSRP-Routern oder wie im Beispiel mit zwei Switches für erhebliche Verwirrung sorgen. Der aktive Switch 1 erhält das Paket aus dem LAN und reicht es sowohl an den Knoten als auch an den zweiten Switch weiter, damit Knoten 2 das Paket erhält. Switch 2 hat nun nichts Besseres zu tun, als das Paket sowohl an den Knoten 2 weiterzugeben als auch an den ersten Switch zurückzuschicken. Einige ältere Switche erzeugten tatsächlich diese Schleife und legten damit das LAN lahm.

Wenn ein Switch Multicast-Adressen nicht über den normalen Mechanismus lernt, muss der Admin ihm per Konfiguration mitteilen, welcher Port Eingang und welcher Ausgang für diese Multicast-Pakete ist. So leitet der Switch jedes Paket genau einmal an das LAN-Interface jedes Knotens. Hängen die beiden Knoten des Clusters an Interface 1 und 2, dann lautet das Kommando beispielsweise für Cisco-Switche:

mac-address-table static 01:02:03:04:05:06 interface FastEthernet0/1 FastEthernet0/2

Bei hochverfügbaren Szenarien mit doppeltem Switch (einem pro Knoten) hilft zudem das Spanning-Tree-Protokoll. Es verhindert Schleifen im Weg zum Ziel.

Der Cluster muss alle zu einer Verbindung gehörenden Pakete demselben Knoten zuweisen. Nur dies verhindert, dass ein Client auf eine Anfrage doppelte Antworten erhält oder dass der Server mit einem Paket nichts anzufangen weiß, weil er die Vorgeschichte nicht kennt. Die Cluster-Software im Netfilter-Paket erledigt das elegant selbstständig.

Zuständigkeitsfrage

Jeder Knoten im Cluster erhält bei der Konfiguration zunächst eine fortlaufende Nummer, im Beispiel die Nummern 1 und 2. Bei jeder neuen Verbindung berechnet das IPtables-Target aus den Verbindungsdaten einen Hash nach Bob Jenkins Verfahren [5] und bildet ihn auf den Wertebereich von 1 bis 2 ab. Ein Knoten weiß danach, ob er für diese Verbindung zuständig ist oder nicht. Zwischen den Knoten ist keine Kommunikation nötig. Über den Status der Verbindung (Connection-Tracking-Funktion) bleibt die Verbindung auch weiter dem Knoten zugeordnet. Welche Daten der Hash-Mechanismus einbezieht, hängt vom Cluster-Modus ab (Tabelle 1).

Tabelle 1:
Cluster-Modi

 

Modus

Funktionsweise

sourceip

Verwendet nur die Source-IP-Adresse für den Hash. Ordnet
daher jedem Client genau einen Knoten zu.

sourceip-sourceport

Verwendet zusätzlich Informationen über den
Source-Port der Applikationen. Die Lastverteilung zwischen den
Knoten wird besser.

sourceip-sourceport-destport

Verwendet zusätzlich Informationen über den
Destination-Port der Applikation.

Im Beispiel soll der Cluster testweise nur ICMP-Echo-Requests beantworten, deshalb ist einzig »sourceip« sinnvoll – ICMP-Pakete haben keine Portnummer. Für Applikationscluster dagegen (zum Beispiel Webserverfarmen) wäre »sourceip-sourceport« die bessere Wahl.

Die Konfiguration des Clusters steckt in einem einzigen IPtables-Befehl pro Knoten. Tabelle 2 erklärt die dabei verwendeten Optionen. Das folgende Beispiel beschränkt den Cluster zudem auf ICMP-Echo-Request (Ping):

iptables -I INPUT -d 192.168.10.3 -p icmp --icmp-type echo-request -j CLUSTERIP --new --hashmode sourceip --clustermac 01:02:03:04:05:06 --total-nodes 2 --local-node 1

Die Konfiguration für Knoten 2 ist fast identisch, nur muss dort bei »–local–node« der Wert »2« stehen. Äußerlich (»ifconf«-Ausgabe) ist den Interfaces nicht anzusehen, dass sie jetzt zum Cluster gehört. Auch der Kernel weiß nicht, dass er auf die IP-Adresse des Clusters reagieren soll. Am einfachsten ändert sich das mit einem »ip«-Aufruf:

ip address add 192.168.10.3/24 dev eth0

Das Kommando ergänzt die Cluster-Adresse als weitere IP für dieses Interface. Danach reagiert der Cluster auf Pings. Wer sich wundert, wo die Konfiguration der Multicast-MAC bleibt: Darum kümmert sich IPtables ganz allein.

Tabelle 2:
Optionen

 

Schalter

Funktion

-d

IP-Adresse des Clusters im LAN

-i

Interface zum LAN

–hashmode

Hash-Modus

–clustermac

MAC-Adresse des Clusters

–total-nodes

Gesamtzahl der Knoten im Cluster

–local-node

Die Nummer Des Knotens im Cluster

Hash-Status

In »/proc/net/ipt_CLUSTERIP/192.168.10.3« ist die Nummer (der Hashwert) hinterlegt, für die dieser Rechner antwortet. Diese Nummer kann man zur Laufzeit ändern, um zum Beispiel den Knoten 2 auch noch für Knoten 1 zuständig zu erklären:

echo "+1" > /proc/net/ipt_CLUSTERIP/192.168.10.3

Dieses Kommando – auf Knoten 2 ausgeführt – bewirkt, dass der Cluster jedes Ping mit zwei Echo-Reply-Paketen quittiert. In der Datei »/proc/net/ipt_CLUSTERIP/IP-Adresse« auf Rechner 2 steht jetzt »1,2«. Ein »echo “-1″…« entzieht dem Knoten die Zuständigkeit für den Hashwert »1«. Der Administrator kann so den ersten Knoten abschalten und die Zuständigkeit für die Verbindungen auf den zweiten Rechner verlagern.

Failover

Ein Skript, das die Zuständigkeit der Knoten automatisch verwaltet, muss

  • den Cluster initialisieren,
  • den Knoten auf Fehler überprüfen,
  • im Fehlerfall den Knoten aus dem Cluster entfernen und die
    Zuständigkeit an einen anderen delegieren und
  • den Knoten weiterhin überprüfen und ihn gegebenfalls
    wieder anmelden.

Das einfache Bash-Skript in Listing 1 fasst die Aufgaben zusammen, ohne Anspruch auf Vollständigkeit. Der Konfigurationsteil (Zeilen 3 bis 11) sammelt die Einstellungen für den Knoten und den Cluster. Danach lädt Zeile 30 das Kernelmodul »ipt_conntrack«. Das Interface erhält anschließend die Clusteradresse und die »INPUT«-Chain wird sicherheitshalber gelöscht (Zeile 32), bevor der »iptables«-Aufruf in der nächsten Zeile den Cluster einrichtet.

Listing 1:
Cluster-Skript

01 #!/bin/bash
02 
03 # Konfiguration der Knoten
04 MYNODE=1
05 DEVICE=eth0
06 OTHERNODE=192.168.20.2
07 
08 # Cluster-Konfiguration
09 CLUSTERIP=192.168.10.3
10 CLUSTERMAC=01:02:03:04:05:06
11 ONLINE=0
12 
13 check_node () {
14   ip link list dev $DEVICE | grep -q UP
15   return $?
16 }
17 
18 failover () {
19   ip address delete $CLUSTERIP/24 dev $DEVICE
20   echo "-$MYNODE" > /proc/net/ipt_CLUSTERIP/$CLUSTERIP
21   ssh $OTHERNODE "echo '+$MYNODE' > /proc/net/ipt_CLUSTERIP/$CLUSTERIP"
22 }
23 
24 recover () {
25   ssh $OTHERNODE "echo '-$MYNODE' > /proc/net/ipt_CLUSTERIP/$CLUSTERIP"
26   ip address add $CLUSTERIP/24 dev $DEVICE
27   echo "+$MYNODE" > /proc/net/ipt_CLUSTERIP/$CLUSTERIP
28 }
29 # Knoten initialisieren
30 modprobe ipt_conntrack
31 ip address add $CLUSTERIP/24 dev $DEVICE
32 iptables -F INPUT
33 iptables -I INPUT -d $CLUSTERIP -i $DEVICE 
34   -p icmp --icmp-type echo-request 
35   -j CLUSTERIP --new --hashmode sourceip 
36   --clustermac $CLUSTERMAC --total-nodes 2 
37   --local-node $MYNODE
38 
39 # Test, ob das Cluster-Interface funktioniert
40 ONLINE=1
41 while (true); do
42   if ( check_node ) then
43     echo "Interface up"
44     if [ $ONLINE -eq 0 ]; then
45       recover
46       ONLINE=1
47     fi
48   else
49     echo "Interface down"
50     if [ $ONLINE -eq 1 ]; then
51       failover
52       ONLINE=0
53     fi
54   fi
55   sleep 1
56 done
57 
58 exit 0

Die Endlosschleife von Zeile 40 bis Zeile 56 ermittelt, ob das Cluster-Interface im »up«-Modus ist (mit Hilfe der »check_node«-Funktion ab Zeile 13). Falls nicht, entfernt »failover« (ab Zeile 18) die IP-Adresse vom Interface, entzieht dem Knoten die Zuständigkeit und überträgt sie per SSH auf den anderen. Dazu müssen beide Knoten ohne Benutzerinteraktion per SSH aufeinander zugreifen.

Recover

Falls das Interface nach einem Fehler wieder online ist, stellt die Recover-Funktion (ab Zeile 24) die ursprüngliche Konfiguration wieder her. Das simple Skript beachtet aber nicht jede Situation. Zum Beispiel könnte das Management-Interface ein Problem melden und die Kommunikation zwischen beiden Knoten stören (Split Brain). Falls kein weiteres Problem auftaucht, hat dieser Fall keine Konsequenzen, da jeder Knoten selbstständig weiterarbeitet. Falls aber ein Failover notwendig wird, geht der schief. Die Hälfte der Kommunikation bleibt unbeantwortet. Ein Backup-Management-Interface (zum Beispiel seriell oder via LAN-Interface) würde die Situation entschärfen.

Zusätzlich müssen die Knoten in einem ausgewachsenen HA-Setup gegenseitig ihren Gesundheitszustand überwachen, sonst könnte einer sterben (etwa Netzteil-Ausfall), ohne dass er dem anderen noch Bescheid sagen kann. In diesem Fall ist wieder eine Split-Brain-Situation möglich, wenn die Knoten sich nicht mehr unterhalten können, sich aber beide weiter am Netz beteiligen. Wie von Linux-HA [1] bekannt, ist hiergegen ein Fencing-Mechanismus nötig.

Und noch viel mehr

Derzeit überlegt der Autor, sein Cluster-Skript in C neu zu schreiben, die Kommunikation zwischen den Knoten per UDP-Socket zu erledigen, mehr als zwei Knoten zuzulassen und die Konfiguration zu standardisieren. Zudem könnten die Tests Parameter wie Prozessorlast, Festplattenplatz, Erreichbarkeit externer Systeme oder Applikationszustand berücksichtigen. Aussichtsreich wäre es auch, die Cluster-Konfiguration als Ressource von Linux-HA verwalten zu lassen und damit die Vorteile von HA und Load Balancing zu bündeln.

Die Cluster-IP-Technik eignet sich auch für hochverfügbare Farmen von Applikationsservern, die ohne großen Aufwand und zentralen Load Balancer zu realisieren sind. Damit beweist das IPtables-Target, dass ein simpler, aber clever eingesetzter Hash-Mechanismus kleine Wunder bewirkt. (fjl)

Infos

[1] Heartbeat: [http://www.linux-ha.org]

[2] Linux Virtual Server: [http://www.linuxvirtualserver.org]

[3] Stonesoft: [http://www.stonesoft.com]

[4] RFC 1812, “Requirements for IP Version 4 Routers”: [http://rfc.net/rfc1812.html]

[5] Bob Jenkins, “A Hash Function for Hash Table Lookup”: [http://www.burtleburtle.net/bob/hash/doobs.html]

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 3 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben