ZIDline
TUWIS++ Performance Tuning
Edmund Dvorak
Jeder Semesterbeginn ist für TUWIS++ ein „Hochlasttest“, und die vergangenen vier Jahre machten verschiedene Performance-Anpassungen nötig.

Motivation

Bis Oktober 2005 lief TUWIS++ als einzelne Zope-Instanz, durch die gestiegene Nutzung und die Ausweitung der Dienste wurde eine Aufteilung auf mehrere Instanzen mittels ZEO (Zope Enterprise Objects) nötig, die die Last für März 2006 und Oktober 2006 gut auffangen konnte.

Im März 2007 wurde der Performance-Flaschenhals von den Clients (die mit der Aufbereitung der Daten beschäftigt waren) zum Datenbankserver verschoben (der die Datenbankabfragen der Clients zu bearbeiten hatte).

Die hierbei auftretenden Probleme waren zweifacher Natur: erstens lief der Datenbankserver in Lastbereiche, wo die Prozessoren mit 100% ausgelastet waren und einige zehn Datenbankprozesse um CPU-Zeit stritten. Zweitens warteten die Zope-Clients auf die Ergebnisse aus der Datenbank und sobald alle möglichen Client-Verbindungen aufgebraucht waren, wurden weitere Anfragen in eine Warteschlange geschoben  Anfragen dauerten dann so lange, bis die in der Warteschlange davor befindlichen Requests abgearbeitet waren  damit konnten unter Umständen minutenlange Wartezeiten entstehen.

Nachdem nun bekannt war, dass der Flaschenhals an der Datenbankmaschine lag, wurden neben der Bestellung einer performanteren Hardware verschiedene Verbesserungen vorgenommen.

Maßnahmen

Eine Änderung der Datenbank-Parameter verbesserte die Antwortzeiten der Datenbank zwar deutlich, diese Maßnahme allein führte jedoch noch nicht zum gewünschten Erfolg, zu Spitzenzeiten wurde die Datenbankmaschine wieder in die Sättigung gefahren.

Nun begann eine recht aufwändige Statement-Optimierung. Mit ORACLE-Tools konnten einzelne Statements ausgemacht werden, die die Spitzenreiter im CPU-Verbrauch waren; zwei Statements waren besonders auffällig, eines konnte um den Faktor 10 beschleunigt werden, das andere wurde in mehrere Einzelstatements zerlegt  dieser Prozess war allerdings erst nach der Hochlastzeit abgeschlossen.

Ein weiterer beobachtbarer Effekt war, dass der ZEO-Server mit den Datenbankprozessen um die CPU kämpfen musste und daher unter Hochlast die Zope-Clients empfindlich bremste. Ein Verlegen des ZEO-Servers auf eine andere Maschine brachte zwar anfangs eine Verbesserung der Antwortzeiten, allerdings konnten die Clients dadurch mehr SQL-Statements absetzen und den Datenbank-Server noch weiter belasten.

Denselben Effekt erzielte man auch, wenn der ZEO-Prozess gegenüber den ORACLE-Prozessen höher priorisiert wurde.

Weitere Untersuchungen des Datenbank-Verhaltens ließen erkennen, dass der Bottleneck der Statement-Parser war. Für einen Großteil der abgesetzten Statements wurde kein Execution-Plan gefunden, und es musste jedes Mal ein neuer erstellt werden.

Bei Tests, wo nur ein einzelnes SQL-Statement ohne  HTML-Aufbereitung der Abfrageergebnisse aufgerufen wurde, konnte der Test in 50% der Zeit abgearbeitet werden, wenn SQL Parameter Binding zum Einsatz kommt.

Daher wurde ein Zope-Addon (ZSQLBindPatch) geschrieben, das die im System vorhandenen ZSQL-Methoden ohne Umschreibearbeit auf SQL Parameter Binding umstellt. Bei einigen wenigen Statements musste das Binding anschließend abgeschaltet werden, weil unter Umständen mehr als 255 Parameter verwendet wurden (Listenaufzählungen). Einige ZSQL-Methoden beinhalteten auch mehrere SQL-Statements, hier kann Binding ebenfalls nicht eingesetzt werden. Diese Statements werden aber ohnehin sehr selten aufgerufen.

Für die Lasttests wurde httperf verwendet. Es lässt sich einfach installieren und es kann eine Reihe von Belastungsszenarien abgebildet werden. Leider stellte sich heraus, dass eine komplette Simulation einer Benutzersitzung damit nicht möglich ist, weil SSL-Abfragen anscheinend nicht korrekt verarbeitet wurden.

Versuche mit curl_load brachten allerdings noch enttäuschendere Ergebnisse, daher wurde letztendlich ein vereinfachtes Lastszenario mit httperf für die Tests herangezogen.

Zunächst wurde die Leistungsfähigkeit der Apache- und Pound-Installation getestet, d.h., es wurde eine statische Seite aufgerufen. Da hierbei Response-Zeiten im Sub-Millisekundenbereich und die Möglichkeit für tausende parallele Abfragen pro Sekunde ermittelt wurden, wird die von Apache und Pound verursachte Last als vernachlässigbar angesehen.

Bei Abfragen von statischen Seiten aus Zope wurde eine Response-Zeit zwischen 15ms und 40ms für eine etwa 1KB große Seite ohne Datenbank-Zugriff ermittelt. Bei parallelen Verbindungen mit 12 ZEO-Clients wurde eine maximale Antwortrate von ca. 344 Antworten/s ermittelt, die ZEO-Clients skalieren bei paralleler Bearbeitung fast linear. Der verwendete Befehl:

httperf --hog --server tuwis.tuwien.ac.at --uri /
--num-conns=1000 --rate 350

Für den Test mit Datenbankanbindung wurde die LVA-Übersichtsseite, wie z.B. "http://tuwis.tuwien.ac.at/zope/tpp/lv/lva_html?num=122040&sem=2007W" als Ziel ausgewählt und es wurde mittels eines python-Scripts ein Satz von 2500 URLs unterschiedlicher LVA generiert. Dieser Satz von URLs wurde mit

httperf --hog --server tuwis.tuwien.ac.at --wlog=n,genurls.dat 
--num-conns=1000 --rate=66

sowohl mit ZSQL-BindPatch als auch ohne ZSQL-BindPatch verwendet.

Ohne Patch ergaben sich für den Test mit 6 ZEO-Clients ca. 33s, die CPU-Last des Datenbank-Servers stieg dabei auf 100%, die ZEO-Clients blieben unter 100%, d.h., auch durch Zuschalten von Clients wäre keine nennenswerte Steigerung des Durchsatzes mehr möglich, da der Datenbank-Server bei dieser Last bereits gesättigt ist.

Mit Patch ergaben sich ca. 21s, dabei blieb die CPU-Last des Datenbank-Servers weit unter 100%, aber die sechs ZEO-Clients wurden nun zu 100% ausgefahren.

Die neue Maschine TUWIS4 besitzt zwei Quad-Core Prozessoren und somit acht Prozessorkerne (die „alten TUWIS1-3 besitzen nur je zwei Prozessorkerne). Zudem weisen die Quad-Core Prozessoren je 4MB Cache auf, im Gegensatz zu 512KB bei den anderen Maschinen.

Da aus technischen Gründen ein Einsatz dieses Rechners als Datenbank-Server zu Semesterbeginn noch nicht möglich war, wurde für jeden Prozessorkern eine ZEO-Client-Instanz aufgesetzt, d.h., acht zusätzliche Instanzen wurden verfügbar.

Mit nunmehr 12 ZEO-Clients ergeben sich bei

httperf --hog --server tuwis.tuwien.ac.at --wlog=n,genurls.dat  
--num-conns=1000 --rate=66

ca. 15s, was genau 1000/66 entspricht. Dabei wird weder die Datenbank-Maschine, noch eine der Client-Maschinen zu 100% belastet. 12 Clients erlauben weit mehr parallele Anfragen, daher wurde die Rate kontinuierlich gesteigert, bis ein Maximum mit ca. 7s bei

httperf --hog --server tuwis.tuwien.ac.at --wlog=n,genurls.dat
--num-conns=1000 --rate=155

gefunden wurde. Hier bleiben Datenbank-Server und ZEO-Clients ebenfalls noch unter 100% CPU-Belastung.

Alle Zeiten wurden mit „heißem“ Cache gemessen, direkt nach dem Neustart der ZEO-Clients oder nach einigen Stunden Inaktivität dauerte der erste Durchlauf etwas länger. Im Betrieb zu Spitzenzeiten ist aber davon auszugehen, dass die Caches „heiß“ sind, da ja häufig verwendete Objekte im Cache landen und auch dort bleiben.

Eine weitere Steigerung wäre durch den Einsatz von weiteren Clients möglich (z.B. vierzehn: 8 auf TUWIS4, je zwei auf TUWIS1, TUWIS2, INFO.ZSERV), oder durch das Erhöhen der Zope-Thread-Anzahl von derzeit 8 auf z.B. 12.

Da allerdings eine Erhöhung der Client-Anzahl oder der Threads auch eine Erhöhung der Anzahl der HTTP- und ORACLE-Prozesse bedeutet, wird hier unter Umständen das eingestellte Limit an Prozessen überschritten. Daher wird ein derartiger Schritt nur bei dringender Notwendigkeit und ganz vorsichtig von den Systemverantwortlichen vorgenommen werden.

Die mit Spannung erwartete Frage war, ob die erreichte Performance-Steigerung (33s -> 7s, das sind 470%) im laufenden Semester auch zu Spitzenzeiten zu Semesterbeginn ausreichen wird, um einen einwandfreien Betrieb zu gewährleisten. Das konnte bereits in der ersten Oktoberwoche eindeutig bejaht werden.

Ausblick

Die gemessene Verbesserung bezieht sich einzig und allein auf die oben angeführte Testlast. Anfragen mit einem höheren Anteil an SQL-Queries werden die Daten-bank stärker auslasten, Anfragen mit hohem Aufbereitungsaufwand erhöhen die Last auf den ZEO-Clients.

Aufwändige Datenbankabfragen werden von der TUWIS4 deutlich schneller bearbeitet als von der TUWIS3, daher wurde nach dem Ansturm zu Semesterbeginn am 1.11.2007 eine Verlagerung der Datenbank auf die TUWIS4 vorgenommen. Oracle 10g scheint ebenfalls performanter zu sein als Oracle 9i, vor allem in Verbindung mit der 64Bit-Architektur und dem größeren zur Verfügung stehenden Speicher.

Unter Hochlast scheint sich der Bottleneck nun von der CPU-Belastung vermutlich langsam zu den durch die Kommunikation unter den Maschinen anfallenden Latenzzeiten zu verschieben, da weder die ZEO-Clients, noch die Datenbank-Maschine im Test mit zwölf Zope-Instanzen eine Auslastung der CPUs zu 100% ermöglichten  die „fehlende“ CPU-Zeit müsste durch Paketlaufzeiten und Protokollwartezeiten zu erklären sein.

Dem könnte man entgegenwirken, indem man entgegen der bisherigen Vorgangsweise versucht, die Datenwege durch den Einsatz weniger leistungsstarker Rechner wieder zu verkürzen. Also beispielsweise vier bis sechs Zope-Instanzen zusammen mit der Datenbank auf einem Rechner zu betreiben (Kommunikation ORACLE/ZOPE läuft dann über loopback statt über LAN) oder die Funktionalität von Pound in den Apache-Server zu legen (eine ganze Kommunikationsebene fällt weg). Wir gehen davon aus, dass die Leistungsfähigkeit preiswerter Rechner schneller wachsen wird als der Leistungsbedarf unserer Anwender und wir werden rechtzeitig dafür Sorge tragen, dass auch in Zukunft die Hochlastzeiten zu Semesterbeginn ausreichend abgedeckt werden.