Lastverteilung von TUWIS++ mit Zope Enterprise Objects
Felix Beer, f.beer@indec.at
Durch die Ausweitung der angebotenen Dienste, insbesondere durch die Prüfungsanmeldung,
ist die Auslastung des TUWIS++-Servers gestiegen. Während des Semesters
führten Anmeldungstermine manchmal zu Performance-Engpässen, jeweils zu
Semesterbeginn (und hier jeweils am ersten Tag des Semesters) kam es zu
absoluten Spitzenauslastungen mit bis zu knapp 1500 offenen Benutzersessions,
was zu Beginn des Wintersemesters 2005 zu relativ langen Antwortzeiten
des Servers führte. Zope Enterprise Objects (ZEO) ermöglicht es nun, eine
Zope-Applikation auf mehreren Rechnern, also als Cluster, zu betreiben.
TUWIS++ basiert auf Zope, einem in Python realisierten Applikationsserver.
Die einzelnen Applikationskomponenten (Objekte, Bilder, ...) werden dabei
in der Regel in einer Datenbank abgelegt, Standard bei Zope ist die ZODB
(Zope Object Database). Eine Speicherung der Objekte in anderen Datenbanken
oder auch im Filesystem ist über APE (adaptable persistence engine) möglich.
Der Zugriff auf relationale Daten ist in Zope standardmäßig über Datenbank-Adaptoren
und ZSQL Methoden gelöst und ist von der Verwendung der ZODB oder APE unabhängig.
TUWIS++ lief bis Oktober 2005 auf einem Dual- Xeon/2.4GHz mit 4 GB RAM,
der auch die relationale Datenbank beherbergte. Es war eine Zope-Instanz
mit Apache als vorgelagertem HTTP-Server konfiguriert. Eine im Oktober
vorgenommene Auslagerung der Datenbank auf einen eigenen Server brachte
nicht die erhoffte Performance-Steigerung.
Zope ist multithreaded, aber ein einziger Prozess. Das führt dazu, dass
bei nur einer Zope-Instanz auch immer nur ein Prozessor mit Zope ausgelastet
werden kann (natürlich können die anderen Prozesse den zweiten Prozessor
auslasten, aber das Hinzufügen von Prozessoren würde zumindest keine Verbesserung
der Zope-Performace bringen)
Werden mehrere Zope-Instanzen eingesetzt, stehen auch mehr Zope-Prozesse
zur Verfügung.
Wenn das Betriebssystem es unterstützt, ist es im Fall von mehreren Instanzen
vernünftig, die einzelnen Zope-Prozesse an jeweils einen Prozessor zu "binden"
(das nennt man auch "setting processor affinity").
Sinnvoll ist dabei das Binden an "physische" Prozessoren, d. h., an tatsächlich
in Hardware vorhandene Prozessoren. Intels Xeon unterstützt Hyperthreading,
da werden - vereinfacht gesagt - die gerade unbenutzten Prozessorkomponenten
zu einem virtuellen zweiten Prozessor zusammengeschaltet. Unter Linux wird
dieser virtuelle Prozessor als zweiter Prozessor gehandhabt.
Die TUWIS2 hat zwei (reale) Xeon-Prozessoren. Die sehen aus Betriebssystemsicht
wie vier CPUs aus, mit den Nummern #0 bis #3, wobei #0 und #1 dem ersten
physischen Prozessor entsprechen und #2 und #3 dem zweiten.
Performancemessungen haben gezeigt, dass mit jeder hinzugefügten Zope-Instanz
auf einer physischen CPU die Leistung gesteigert werden kann, das Hinzufügen
weiterer Prozesse auf den virtuellen CPUs jedoch kaum Gewinn bringt.
Aus diesem Grund werden auf dieser Hardware nun zwei Zope-Instanzen eingesetzt.
Das Pflegen getrennter Instanzen wäre jedoch recht mühselig, gäbe es nicht
ZEO (Zope Enterprise Objects). ZEO macht im Wesentlichen nichts anderes,
als eine gemeinsame ZODB für mehrere Zope-Instanzen (ZEO-Clients) zu verwalten
und sich dabei um Dinge zu kümmern wie Konfliktauflösung und Informieren
der Clients, wenn Objekte in der Datenbank geändert wurden. Da ZEO seine
Dienste per TCP anbietet, können Clients auch leicht auf weiteren Servern
aktiviert werden.
TUWIS++ läuft nun mit insgesamt vier Instanzen über zwei Server verteilt.
Auf dem Master läuft neben zwei Zope-Instanzen auch die Datenbank und der
ZEO-Server, auf der zweiten Maschine laufen zwei weitere Instanzen größtenteils
ungestört von anderen Prozessen.
Lastverteilung mit ZEO
Die Verteilung der Anfragen auf die verschiedenen Instanzen übernimmt -
in Ermangelung eines geeigneten Modules a la mod_backhand für Apache2 -
ein eigener Reverse Proxy/Load Balancer,
pound (
http://www.apsis.ch/pound/).
Pound teilt die Benutzeranfragen leicht konfigurierbar auf mehrere Backends
(in unserem Fall Zope-Instanzen) auf, wobei jedem Backend eine Gewichtung
zugeordnet werden kann. Im Hochlastbetrieb hat sich eine Gewichtung von
1:5 zwischen Master und zweitem Server als günstig herausgestellt, damit
wird auf beiden Maschinen in etwa dieselbe Last erzeugt und Anfragen werden
auch bei Hochlast noch relativ flüssig abgearbeitet.
Pound/ZEO bietet einen weiteren Vorteil für die Wartung - die Sessiondaten
werden in einer weiteren, temporären ZODB gehalten, die ebenfalls über
ZEO verwaltet wird. Das ist notwendig, damit die Instanzen auch auf dieselben
Sessions zugreifen können, und über diesen Mechanismus wird auch ermöglicht,
einzelne Instanzen zu Wartungszwecken herunterzufahren, ohne dass die Sessions
der Benutzer ungültig werden.
Pound erkennt Instanzen, die gerade nicht aktiv sind, und leitet die Anfragen
automatisch auf andere, aktive Instanzen um. Alle 30 Sekunden prüft Pound,
ob eine Instanz wieder aktiv wird, und bindet diese Instanz dann vollautomatisch
wieder ein.
Beim Installieren neuer Produkte oder bei Upgrades kann so ein weitgehend
ungestörter Betrieb aufrechterhalten werden.
Für die Zukunft ist die Erprobung von "temporären ZEO-Clients" vorgesehen,
d. h., zu Hochlastzeiten könnten einfach einige "Reserve-PCs" von einer
CD gebootet und als weitere Instanzen eingebunden werden, womit die periodischen
Spitzen sehr kostengünstig abgedeckt werden könnten.