Möchte der Admin die Last, die eine große Anzahl Aufträge erzeugt, auf verschiedene Maschinen gleichmäßig verteilen, greift er auf Load Balancer zurück. Kommerzielle Varianten sind oft nicht billig – Load Balancer lassen sich aber auch im Eigenbau realisieren, wie dieser Beitrag demonstriert.
Ein Ziel bei der Lastverteilung ist, dass sie für den Client völlig transparent sein soll. Der Benutzer kommuniziert mit einem einzigen Server und erfährt nie, dass sich dahinter ein ganzer Serververbund verbirgt. Auf diese Weise verteilt sich im Hintergrund nicht nur die Last, es ergibt sich auch noch ein zweiter Vorteil: Jederzeit darf einer der Server ausfallen oder lässt sich – etwa zu Wartungszwecken – auch gezielt abschalten, ohne dass dies den Betrieb stören würde.
Wie lässt sich ein solches Load Balancing bewerkstelligen? Da gibt es einmal kommerzielle Angebote. Deren Markt ist hart umkämpft. Bekannte Produkte wie F5 oder A10 findet man in vielen Rechenzentren. Dass aber auch der Linux-Kernel seit über 15 Jahren mit dem Netfilter-Modul IPVS [1] eine völlig kostenlose und umfassende Load-Balancing-Funktion bietet, ist weniger bekannt.
Die Idee der Lastverteilung unter Linux mit IPVS (IP Virtual Server) hatte bereits 1999 Wensong Zhang in einem Arbeitspapier [2] für die Linux Expo vorgestellt. Ziel der Entwickler war es, “einen hochperformanten und hochverfügbaren Linux-Server mittel Cluster-Technologie zu schaffen, der gute Skalierbarkeit, Zuverlässigkeit und Administrierbarkeit bietet”.
Terminologie
Zum besseren Verständnis der folgenden Erläuterungen sind einige Begriffsdefinitionen unumgänglich.
Linux Virtual Server: Bezeichnet das Gesamtpaket zur Lastverteilung von Anfragen, das aus mehreren Servern besteht, die sich dem Client gegenüber als ein logischer und hochverfügbarer Server präsentieren. Ein virtueller Server verfügt dabei über einen oder mehrere Sockets (jeweils IP-Adresse plus Port), die auf Anfragen von Clients reagieren. Die Beantwortung der Anfragen übernimmt ein Realserver. Ein Virtual Server ist die virtuelle Instanz, hinter dem sich ein oder mehrere Realserver verbergen.
Realserver: Eine physische Maschine in einer Virtual-Server-Umgebung, die die Anfragen von Clients beantwortet. Ein typischer Realserver wäre ein Webserver, der an Clients Webseiten ausliefert. In einer Linux-Virtual-Server-Umgebung ist zwingend mehr als ein Realserver nötig, um damit eine Lastverteilung zu erreichen. Ein Realserver kann je nach Betriebsart jedes Gerät sein, das einen TCP/IP-Stack besitzt. Also neben einem Server oder einer Workstation auch ein Printserver oder eine IP-Kamera.
VIP: Die virtuelle IP-Adresse, die die Clients zur Kommunikation nutzen. Hinter der VIP existieren für den Client transparent mehrere Realserver.
Ipvsadm: Software zur Aktivierung, Verwaltung und Überwachung von IPVS im Linux-Kernel. Ipvsadm bietet die Möglichkeit, Statistiken, Zuordnungen und weitere Informationen anzuzeigen. Zusätzlich kann Ipvsadm auch als Dienst laufen (Option »–start-daemon«) und sorgt dann für eine Synchronisation der Zuordnungstabelle unter mehreren Virtual-Servern. Dies ist in Clusterumgebungen hilfreich.
Ldirector: Wrapper-Dienst für Ipvsadm. Er findet häufig als Ressource für Linux-HA Verwendung. Ein großer Vorteil von Ldirector ist die Möglichkeit, Ressourcen auf Verfügbarkeit zu prüfen. Beispielsweise wäre es möglich, einen Webserver kontinuierlich nach einer Datei zu befragen und je nach Erfolg eine Aktion auszulösen, etwa einen fehlerhaften Realserver aus dem Verbund zu entfernen.
Betriebsarten
IPVS kennt eine Reihe unterschiedlicher Betriebsarten, die sich darin unterscheiden, ob die Realserver eine Anpassung benötigen oder nicht (Tabelle 1). Das hier beschriebene Beispiel verwendet die Betriebsart NAT/Full-NAT, die die einfachste Methode darstellt und ohne Anpassung der Realserver auskommt.
|
Modus |
Anpassung der Realserver nötig? |
Umfang der Anpassung |
|---|---|---|
|
NAT oder Full-NAT |
nur bei NAT |
Setzen des Load Balancers als Default-Gateway |
|
TUN |
ja |
Deaktivierung von ARP-Replies, Aktivierung von IP-Tunneling |
|
Direct Routing |
ja |
Deaktivierung von ARP-Replies, zusätzliches Interface nötig |
Die Betriebsart NAT (Network Address Translation) nutzt die Technik der Adressumsetzung. In diesem Modus läuft der gesamte Netzwerkverkehr ausschließlich über den Load Balancer. Dieser veranlasst auch, dass die an ihn gerichteten Pakete eine neue Ziel-IP-Adresse erhalten, die zu einem der Realserver gehört. Dieser Realserver bekommt dann das umadressierte Paket zugestellt (Abbildung 1).

Abbildung 1: Weg der Pakete im Modus NAT. Der Client spricht eine virtuelle IP-Adresse an, die NAT gegen die eines Realservers austauscht.
In der erweiterten Betriebsart Full-NAT erfolgt zusätzlich auch ein Umschreiben der Quell-IP-Adresse (Source-NAT), sodass die Antwortpakete direkt den Load Balancer erreichen (Abbildung 2).

Abbildung 2: Die Pakete der Realserver erreichen den Client, der mit ihnen aber nichts anfangen kann, weil er den Realserver nicht angesprochen hatte.
Dem Standard entsprechend würden die Antwortpakete vom Realserver zum Client gelangen. Doch der würde sie verwerfen, weil er nie mit dem Realserver kommuniziert hat. Er verwendete stattdessen ja die VIP des Virtual-Servers.
Dieses Problem ist unter dem Stichwort Destination NAT Mistake bekannt. Um es zu lösen, müssen alle Realserver den IPVS als Default-Gateway nutzen. So kann auch die Antwort vom Realserver durch NAT wieder umgeschrieben werden (Abbildung 3). Der IPVS sorgt dann auch dafür, dass die Antwortpakete der Realserver an den Client eine neue Absenderadresse erhalten.

Abbildung 3: Im Full-NAT-Modus schreibt der Load Balancer auch die Absenderadresse in die Adresse um, die der Client ursprünglich angegeben hatte.
Die Implementierung basiert auf dem IP-Masquerading-Code von Linux. Zusätzlich wurden Teile von Steven Clarke’s Port-Forwarding-Code genutzt. Im sorgenfreieren Modus Full-NAT muss der Load Balancer nicht mehr der Default-Gateway der Realserver sein.
Verteilmethoden
Die Verteilung der Clientanfragen an die Realserver kann nach unterschiedlichen Verteilungsmethoden erfolgen:
- Round-Robin Scheduling (»ip_vs_rr.ko«)
- Weighted Round-Robin Scheduling (»ip_vs_wrr.ko«)
- Least-Connection Scheduling (»ip_vs_lc.ko«)
- Weighted Least-Connection Scheduling (»ip_vs_wlc.ko«)
- Locality-Based Least-Connection Scheduling (»ip_vs_lblc.ko«)
- Locality-Based Least-Connection with Replication Scheduling (»ip_vs_lblcr.ko«)
- Destination Hashing Scheduling (»ip_vs_dh.ko«)
- Source Hashing Scheduling (»ip_vs_sh.ko«)
- Shortest Expected Delay Scheduling (»ip_vs_sed.ko«)
- Never Queue Scheduling (»ip_vs_nq.ko«)
Die folgenden Beispiele verwenden Round-Robin Scheduling. Der Round-Robin-Algorithmus verteilt eingehende Anfragen abwechselnd auf alle verfügbaren Realserver. Man könnte auch sagen, er verteilt reihum, unabhängig von der momentanen Auslastung eines Servers oder seiner Antwortzeit im Netzwerk.
Konfiguration
Für die Konfiguration des Load Balancers steht das Kommandozeilentool »ipvsadm« bereit. Ipvsadm bildet die Schnittstelle zum Kernelmodul »ip_vs«. Ipvsadm läuft standardmäßig nicht als Dienst und wird – analog zu »sysctl« – zum Setzen von Kernelparametern verwendet. Die eigentliche Konfiguration des Load Balancers erfolgt zeilenweise. Das Tool setzt die Einstellungen danach automatisch im Kernel.
Sie sind allerdings nicht persistent. Ein Entladen des »ip_vs«-Moduls entfernt auch die Einstellungen. Die einmal angefertigte Konfiguration lässt sich jedoch mit der Option »–save« auf die Standardausgabe sichern und mit »–restore« erneut einspielen.
Ipvsadm steht aktuell in allen gängigen Linux-Distributionen über den Paketmanager zur Verfügung. Die Installation unter Debian und Ubuntu gelingt demzufolge mit:
apt-get install ipvsadm
In der Betriebsart NAT/Full-NAT übernimmt der Load Balancer Paketweiterleitungsaufgaben. Hierzu sind die Optionen »ip_forward« sowie das Connection-Tracking für Virtual-Server zu aktivieren:
echo "1" > /proc/sys/net/ipv4/ip_forward echo "1" > /proc/sys/net/ipv4/vs/conntrack
Diese Einstellungen sollten persistent sein, der Admin hinterlegt sie in der systemeigenen »sysctl.conf«.
Damit der Load Balancer auf ARP-Requests für die VIP im lokalen Netz reagiert, ist es nötig, einen IP-Alias auf einem Netzwerkinterface anzulegen:
ip address add 192.168.0.100/24 dev eth0
Auch dies automatisiert man am besten über die jeweilige Konfigurationsdatei der Distribution, unter Debian/Ubuntu also »/etc/network/interfaces«.
Eine typische Konfiguration mit wenigen Realservern besteht dann aus drei Schritten. Im ersten konfiguriert der Admin die VIP inklusive Port und Time-out-Werten und wählt den Load-Balancer-Algorithmus. Der zweite fügt die Realserver dem Virtual-Server hinzu. Abschließend hinterlegt der Admin in der Betriebsart Full-NAT die nötige IPtables-SNAT-Regel, die jeweils VIP-bezogen ist.
Ipvsadm nutzt der Admin dabei zum Auslesen der derzeitigen Konfiguration und der aktiven Sessions beziehungsweise der Zuordnungen im Kernel. Natürlich könnte er auch mit Bordmitteln (»cat«, »tail«, »more«) direkt auf das »/proc«-Dateisystem zugreifen. Die Interpretation der Werte erfordert dann jedoch einiges an Übung. Deshalb ist »ipvsadm« an dieser Stelle schon eine deutliche Erleichterung.
Im Einzelnen geht es also zunächst darum, die VIP des Virtual-Servers zu definieren (»-A -t«) und den Betriebsmodus auf Round-Robin festzulegen (»-s«) sowie die Persistenz auf 4 Stunden (»-p 14400«) einzustellen:
ipvsadm -A -t 192.168.0.100:80 -s rr -p 14400
Danach ist der erste Realserver zum Verbund hinzuzufügen (»-r«) und der Operationsmodus auf »masquerading« (NAT) zu setzen (»-m«):
ipvsadm -a -t 192.168.0.100:80 -r 192.168.0.200:80 -m
Nach demselben Schema folgt ein zweiter Realserver:
ipvsadm -a -t 192.168.0.100:80 -r 192.168.0.201:80 -m
Aktivieren der passenden SNAT-Regel:
iptables -t nat -A POSTROUTING -m ipvs --vaddr 192.168.0.100/32 --vport 80 -j SNAT --to-source 192.168.0.100
Dabei verbirgt sich hinter »–vaddr« die VIP, »–vport« bezeichnet den hinterlegten Port und »–to-source« die IP des Load Balancers.
Dies sorgt dafür, dass ausgehende Pakete des Clients – über den Load Balancer – ab sofort als Quell-IP die IP des Load Balancers tragen und dass sie erst mit dieser Änderung beim Client landen, der sie deshalb nicht mehr verwirft.
Ohne obige SNAT-Regel muss der Load Balancer der Default-Gateway für die Realserver sein. Dies ist nur möglich, wenn sich Clients und Realsever in getrennten Subnetzen befinden. Andernfalls senden die Realserver die Anfragen direkt an die Clients, da diese einfach per ARP-Request zu finden sind. Die Clients verwerfen dann jedoch die Antwortpakete, da kein gültiger Drei-Wege-Handshake zwischen den Kommunikationspartnern zustande gekommen war.
Was bewirkt die Konfiguration bis zu diesem Punkt? Anfragen an den Socket 192.168.0.100 auf Port 80 werden jetzt abwechselnd an die Realserver 192.168.0.200 und 192.168.0.201 verteilt. Eine einmal bestehende Zuordnung hat eine Persistenz von 4 Stunden (14400 Sekunden).
Zwingend notwendig ist, dass auf den Realservern auf Port 80 ein Webserver lauscht, um Anfragen zu beantworten.
In Aktion
Die Konfiguration ist vom Client aus einfach zu testen:
curl http://192.168.0.200
Zurück kommt der Quelltext der Default-Seite des Webservers (Listing 1). Ein Aufruf von »ipvsadm« in Listing 2 gibt den aktuellen Status der Konfiguration aus. Hier zeigt sich, dass ein Client drei HTTP-Verbindungen aufgebaut hat, die aber bereits wieder terminiert wurden (»inactive«). Wegen der Persistenz landet dieser Client für die nächsten knapp 4 Stunden auf demselben Realserver.
Listing 1
Default-Page
01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
02 <html xmlns="http://www.w3.org/1999/xhtml">
03 <head>
04 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
05 <title>Apache2 Debian Default Page: It works</title>
06 <style type="text/css" media="screen">
07 * {
08 margin: 0px 0px 0px 0px;
09 padding: 0px 0px 0px 0px;
10 }
Listing 2
ipvsadm -Ln
01 IP Virtual Server version 1.2.1 (size=4096) 02 03 Prot LocalAddress:Port Scheduler Flags 04 -> RemoteAddress:Port Forward Weight ActiveConn InActConn 05 TCP 192.168.0.100:80 rr persistent 14400 06 -> 192.168.0.200:80 Masq 1 0 0 07 -> 192.168.0.201:80 Masq 1 0 3
In der Praxis kommt es vor, dass Realserver hinter einem Load Balancer nicht mehr erreichbar sind. Ohne weitere Vorkehrungen würde der Load Balancer diese Server dennoch weiter mit Anfragen überhäufen. Um das zu vermeiden, gilt es, Ausfälle zu erkennen und Maßnahmen zu ergreifen. Zu diesem Zweck wurde »ldirectord« entwickelt.
Ldirectord selbst kann als Frontend für »ipvsadm« verstanden werden. Die Überwachung der Realserver mit »ldirectord« geht weit über einen einfachen Ping-Check oder die Prüfung eines offenen Ports hinaus. Ldirectord bietet für die Protokolle DNS, FTP, HTTP, HTTPS, HTTP Proxy, IMAP, IMAPS, LDAP, MySQL, NNTP, Oracle, PgSQL, POP, POPS, Radius, Simple TCP, SIP, SMTP und Submission erweiterbare Checks auf Anwendungsebene an. Die lassen sich durch externe Skripts noch ergänzen.
Zusätzlich ist es möglich, die Konfiguration von Virtual-Servern auf Grundlage der Ldirectord zu automatisieren, um sich Tipparbeit zu sparen. Die SNAT-Regeln sind allerdings in jedem Fall manuell einzugeben. Das oben demonstrierte Setup lässt sich unter Benutzung von Ldirectord erzeugen, indem der Admin ein File »/etc/ha.d/ldirectord.cf« mit dem Inhalt aus Listing 3 anlegt. Anschließend startet er den Dienst neu und kontrolliert das Ergebnis im Ldirectord-Log, das Einträge enthalten sollte, wie sie beispielsweise Listing 4 zeigt.
Listing 3
ldiretord.cf
01 checktimeout=3 02 checkinterval=5 03 autoreload=yes 04 logfile="/var/log/ldirectord.log" 05 quiescent=no 06 virtual=192.168.0.100:80 07 real=192.168.0.200:80 masq 08 real=192.168.0.201:80 masq 09 scheduler=rr 10 protocol=tcp 11 checktype=connect 12 checkport=80 13 peristent=14400
Listing 4
ldirectord.log
01 root@s1:/home/sb# tailf /var/log/ldirectord.log 02 [Tue Apr 10 10:46:57 2018|ldirectord|7809] Starting Linux Director v1.186-ha as daemon 03 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Added virtual server: 192.168.0.100:80 04 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Added real server: 192.168.0.200:80 (192.168.0.100:80) (Weight set to 1) 05 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Deleted real server: 192.168.0.200:80 (192.168.0.100:80) 06 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Added real server: 192.168.0.201:80 (192.168.0.100:80) (Weight set to 1) 07 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Deleted real server: 192.168.0.201:80 (192.168.0.100:80) 08 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Resetting soft failure count: 192.168.0.200:80 (tcp:192.168.0.100:80) 09 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Added real server: 192.168.0.200:80 (192.168.0.100:80) (Weight set to 1) 10 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Resetting soft failure count: 192.168.0.201:80 (tcp:192.168.0.100:80) 11 [Tue Apr 10 10:46:57 2018|ldirectord|7812] Added real server: 192.168.0.201:80 (192.168.0.100:80) (Weight set to 1)
Fällt nun ein Realserver aus, wird er aus der Verteilung entfernt und der Vorgang protokolliert. Ein nochmaliger Aufruf von »ipvsadm -L« reflektiert die verminderte Anzahl Realserver. Kehrt der ausgefallene Realserver repariert zurück, integriert ihn der Load Balancer erneut.
Läuft IPVS auf einem einzelnen Server, schafft man sich hierdurch einen Single Point of Failure (SPOF). In der Praxis werden deshalb die Komponenten »ipvsadm« und »ldirectord« oft in einem Pacemaker-Cluster als Ressourcen betrieben. Ldirectord selbst bietet erweiterte Optionen, die die Hochverfügbarkeit steigern. Mit der Konfigurationsvariablen »callback« besteht eine Möglichkeit der Cluster-weiten Synchronisierung der eigenen Konfiguration. Mit der Option »fallback« ist eine Status-Seite einblendbar.
Fazit
IPVS stellt das nötige Handwerkszeug bereit, um damit auf Layer 4 Anfragen zu verteilen. Kommerzielle Anbieter bedienen mit ihren Produkten zusätzlich noch höhere OSI-Schichten. Dadurch kann der Balancer zum Beispiel anhand aufgerufener HTTP-URLs entscheiden, welcher Realserver eine Anfrage erhält, oder SSL-Verbindungen bereits auf dem Load Balancer terminieren, um die Systeme dahinter zu entlasten.
Load Balancer als Hardware-Appliance verwenden häufig zusätzlich performantere und für Routing/Switching optimierte Hardware. Diese Funktionen lassen sich die Anbieter aber teuer bezahlen. Ein kommerzielles Load-Balancer-Paar übersteigt schnell selbst die Anschaffungskosten eines Mittelklassewagens.
Die kostenlose Alternative IPVS punktet mit Geschwindigkeit, da die Paketverarbeitung direkt im Linux-Kernel stattfindet. Das zugrunde liegende Netfilter-Subsystem ist sehr ausgereift und seit Jahrzehnten erprobt. Durch die offene Architektur lässt sich das System einfach erweitern. Nicht umsonst setzen Riesen wie Facebook, Google, Docker, Red Hat, Wikipedia und Alibaba seit Jahren auf IPVS [4].
Infos
-
Git-Repository: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/netfilter/ipvs
-
Paper zu Linux Virtual Server: http://www.linuxvirtualserver.org/linuxexpo.html
-
IPVS Full NAT Support: https://lwn.net/Articles/395779
-
IPVS für Docker-Container: https://de.slideshare.net/Docker/kernel-load-balancing-for-docker-containers-using-ipvs






