Apache: Erstellen eines Session-kompatiblen Loadbalancers unter Verwendung von mod_proxy_balancer (Debian Etch)
Version 1.0
Author: Falko Timme <ft [at] falkotimme [dot] com>
Seit Apache Version 2.1 ist ein neus Modul namens mod_proxy_balancer verfügbar, mit dem Du ein System, auf dem Apache installiert ist, in einen Loadbalancer umwandeln kannst. Dieser Loadbalancer ruft angeforderte Seiten von einem oder mehreren backend Web Servern auf und sendet sie an den Computer des Benutzers. Benutzer gewinnen den Eindruck, dass sie sich nur mit einem Server (dem Loadbalancer) beschäftigen, obwohl hinter dem Loadbalancer eigentlich mehrere Systeme stehen, die die Anfragen des Benutzers ausführen. Mit einem Loadbalancer kannst Du die durchschnittliche Auslastung auf Deinen Web Servern verringern. Eine wichtige Funktion von mod_proxy_balancer ist, dass es Sessions verfolgen kann, was bedeutet, dass es ein Benutzer immer mit dem gleichen backend Web Server zu tun hat. Die meisten Webseiten sind heutzutage Datenbank-basiert mit Benutzer Logins etc. Man würde komische Ergebnisse erhalten, wenn sich ein Benutzer auf einem backend Web Server anmeldet und seine nächste Anfrage dann zu einem anderen backend Web Server gesendet wird, was bedeutet, dass er wieder abgemeldet wird. Das kannst Du mit mod_proxy_balancer verhindern.
Ich übernehme keine Garantie, dass dies auch bei Dir funktioniert!
1 Vorbemerkung
Es sollte zur Kenntnis genommen werden, dass ein Loadbalancer die Auslastung auf Deinen backend Web Servern verringern kann, er bietet allerdings keine hoch-Verfügbarkeit an (solange Du nur einen Loadbalancer verwendest)! Ein einzelner Loadbalancer ist eine Schwachstelle. Wenn Du eine hoch-Verfügbarkeit möchtest, solltest Du mindestens zwei Loadbalancer (z.B. einen als hot-standby) verwenden.
Ich werde in diesem Beispiel drei Server verwenden: einen Loadbalancer mit der Adresse www.example.com / example.com und zwei backend Server mit den Adressen http1.example.com und http2.example.com.
Alle drei Server verwenden Debian Etch als Betriebssystem und auf allen drei Systemen ist Debians Apache2 installiert (die Version ist 2.2.3, mod_proxy_balancer ist also standardmäßig integriert). Auf http1.example.com und http2.example.com habe ich eine Datenbank-basierte Web Anwendung installiert: phpBB2, eine beliebte Forum Software. Beide phpBB2 Installationen sind identisch und verwenden die gleiche Datenbank. Für die Fehlersuche habe ich in beiden Installationen einen kleinen Unterschied eingebaut: Wenn die Seite von http1.example.com zugestellt wird, wird http1.example.com im Header angezeigt:
Und wenn sie von http2.example.com zugestellt wird, wird http2.example.com angezeigt:
Somit kann ich kontrollieren, ob Sessions von mod_proxy_balancer richtig gehandhabt werden. Auf einem Produktionssystem wären beide Seiten natürlich gleich.
Das Verfolgen der Sessions ist in mod_proxy_balancer etwas knifflig, da es ein bestimmtes Cookie Format erwartet und der Name der Sessionvariable von Anwendung zu Anwendung unterschiedlich sein kann. Gott sei Dank habe ich diese Seite gefunden: http://www.markround.com/archives/33-Apache-mod_proxy-balancing-with-PHP-sticky-sessions.html die eine großartige und einfache Lösung für dieses Problem bereit hält, die ich hier anwenden werde.
2 Die Backend Server vorbereiten
Zuerst müssen wir unsere backend Web Server http1.example.com und http2.example.com vorbereiten. Wir aktivieren mod_rewrite wie folgt:
http1.example.com / http2.example.com:
a2enmod rewrite
/etc/init.d/apache2 force-reload
Dann öffnen wir die Apache vhost Konfiguration unserer phpBB2 Site auf http1.example.com und fügen folgende Zeilen hinzu:
http1.example.com:
[...] RewriteEngine On RewriteRule .* - [CO=BALANCEID:balancer.http1:.example.com] [...] |
(Pass auf, dass Du http1 und .example.com entsprechend Deiner Vorstellungen ersetzt!)
Starte Apache danach neu:
http1.example.com:
/etc/init.d/apache2 restart
Jetzt führen wir das Gleiche auf http2.example.com aus:
http2.example.com:
[...] RewriteEngine On RewriteRule .* - [CO=BALANCEID:balancer.http2:.example.com] [...] |
(Pass auf, dass Du http2 und .example.com gemäß Deinen Vorstellungen ersetzt!)
Starte Apache danach neu:
http2.example.com:
/etc/init.d/apache2 restart
Mehr müssen wir auf den backend Servern nicht konfigurieren.
3 Konfiguration des Loadbalancers
Auf unserem Loadbalancer www.example.com müssen wir einige Apache Module aktivieren:
www.example.com:
a2enmod proxy
a2enmod proxy_balancer
a2enmod proxy_http
a2enmod status
und starten dann Apache neu:
/etc/init.d/apache2 force-reload
Ich gehe davon aus, dass wir auf dem Loadbalancer keine anderen Webseiten ausführen, also können wir Debians Standard Dokumenten-Root /var/www für unseren Loadbalancer verwenden.
mod_proxy_balancer hat einen „Balancer Manager“, ein kleines Web Interface, auf dem Du ein paar Einstellungen optimieren kannst. Wir erstellen dafür das Verzeichnis /var/www/balancer-manager, das wir mit einem Passwort schützen, so dass nur wir Zugriff darauf haben:
mkdir /var/www/balancer-manager
htpasswd -c /var/.htpasswd admin
(Du kannst admin mit einem beliebigen Benutzernamen ersetzen.)
vi /var/www/balancer-manager/.htaccess
AuthType Basic AuthName "Members Only" AuthUserFile /var/.htpasswd <limit GET PUT POST> require valid-user </limit> |
Nun kommen wir zur vhost Konfiguration des Loadbalancers. Apaches Standard vhost Konfiguration auf Debian Etch befindet sich in /etc/apache2/sites-available/default, also ersetzen wir sie mit unserer eigenen Konfiguration:
cp /etc/apache2/sites-available/default /etc/apache2/sites-available/default_orig
cat /dev/null > /etc/apache2/sites-available/default
vi /etc/apache2/sites-available/default
NameVirtualHost * <VirtualHost *> ServerName www.example.com ServerAlias example.com DocumentRoot /var/www/ ProxyRequests Off <Proxy *> Order deny,allow Allow from all </Proxy> ProxyPass /balancer-manager ! ProxyPass / balancer://mycluster/ stickysession=BALANCEID nofailover=On ProxyPassReverse / http://http1.example.com/ ProxyPassReverse / http://http2.example.com/ <Proxy balancer://mycluster> BalancerMember http://http1.example.com route=http1 BalancerMember http://http2.example.com route=http2 ProxySet lbmethod=byrequests </Proxy> <Location /balancer-manager> SetHandler balancer-manager Order deny,allow Allow from all </Location> </VirtualHost> |
Es ist sehr wichtig, dass Du alle Slashes (/) GENAUSO wie im Beispiel gezeigt wird setzt, vor allem die Slashes am Ende von Adressen!