Beim Testen der Performance wird dem System sowohl mit, als auch ohne Last auf den Zahn gefühlt. Idealerweise ist das gesamte Team bei der Suche nach den Flaschenhälsen eingebunden. Oft gibt es nach Modifikationen im System Folgemessungen, deren Ergebnisse die weiteren Schritte beeinflussen.
Der 3. Teil unserer Blogreihe „Last- und Performancetest“ gibt Ihnen einen kleinen Einblick in ausgewählte Situationen, die wir in der Praxis erlebten. Anhand ihnen kommentieren und bewerten wir die jeweilige Problematik.
Die Interpretation von Messergebnissen und die Identifikation möglicher Flaschenhälse ist eine Herausforderung für jeden Performancetest-Engineer. Die Praxis zeigt, dass durch Diskussion der Ergebnisse im Team die Problembereiche und Ursachen für schlechte Performance sehr viel schneller gefunden werden. Wenn sich der Tester ins „stille Kämmerchen“ zurückzieht und auf sich selbst gestellt ist, wird er erfahrungsgemäss weniger Probleme identifizieren. Die Unterstützung durch Entwickler oder DBAs ist daher stets hilfreich.
Die Metriken
Welche Metriken können gemessen und aufgezeichnet werden?
Um die Systemperformance zu analysieren, müssen Messungen durchgeführt werden. Dies erfolgt an den Servern wie auch an den Clients. Metriken sind für uns Performancetester die Grundsubstanz für die Analyse des zu testenden Systems. Sie bilden oft die Entscheidungsgrundlage für weitere Messungen.
Zu den Messungen am Server zählen hauptsächlich:
- Speichernutzung (Auslastung von RAM, Festplatte - in GB und Prozent)
- CPU Auslastung (Belastung des Prozessors in Prozent)
- Netzwerk Auslastung (in KB/s oder MB/s und Prozent)
Zu den Messungen am Client gehören häufig:
- Antwortzeit über die Zeit (ms über Minuten, Stunden oder auch Tage)
- Anfragen/Sekunde (jede einzelne Anfrage als Summe in einem gewissen Zeitraum, z.B. pro Sekunde)
- Byte Durchsatz/Sekunde (wie gross ist der Datenaufwand je Anfrage)
- Aktive Threads/Sekunde (wie viele parallel laufende „User“ sind in Verwendung)
- Transaktionen über die Zeit (Anzahl an Transaktionen über die Testdauer)
Wie die Messungen graphisch dargestellt werden, ist in den Diagrammen der nachfolgenden Abschnitte ersichtlich.
Das System an seinen Grenzen
Ein häufig anzutreffendes Phänomen zeigt das nachfolgende Bild. Geprüft wurde hier ein Geschäftsprozess mit vier Schritten. Im nachfolgenden Diagramm sind der Übersicht halber nur die erfolgreich durchgeführten Transaktionen dargestellt. Infolge eines Ausbaus der Infrastruktur (Hinzunahme eines 2. Servers) wurden in einer Vergleichsmessung die Anfragen auf 2 Servern verteilt. Dadurch konnte in einer vorgegebenen Zeit mehr als die doppelte Menge an Transaktionen gestartet werden. Diese Steigerung ist im Diagramm unter dem Schritt 1 erkennbar. Beim Blick auf den 2. Schritt muss dann festgestellt werden, dass dieser sehr viel weniger erfolgreiche Transaktionen verzeichnet. Der Trend setzt sich bei den Folgeschritten nicht mehr ganz so stark fort.
Vergleichs-Test: Anzahl an erfolgreichen Transaktionen eines Workflows, aufgeschlüsselt auf die Teilschritte
An diesem Beispiel ist zu erkennen, dass im Fall von 2 Servern eine sehr viel grössere Anzahl an Prozessen gestartet werden konnte. Betrachtet man jedoch die Anzahl der erfolgreich abgeschlossenen Prozesse, dann stellt man fest, dass diese in beiden Situationen fast identisch hoch sind. Die Aufstockung durch einen zweiten Server brachte keine nennenswerte Verbesserung.
In Analysen wurde die Applikation selbst als Flaschenhals identifiziert. Die Applikationsinstanzen wurden verdoppelt und trotzdem erfolgte kein entsprechend höherer Durchsatz. Die Vermutung liegt nahe, dass das Problem bei der Art und Weise des Zugriffs auf die Datenbank zu suchen ist. Die Datenbank selbst hat sich gelangweilt. So entstand ein Verarbeitungs-Stau innerhalb der Anwendung, der ab einer bestimmten Transaktionsrate nur noch zu Fehlern führte – Bad Gateway. Das bedeutet, dass die anderen Komponenten, wie beispielsweise der Reverse-Proxy, kein “Lebenszeichen” von der Anwendung erhalten haben und diese demzufolge als “tot” deklarierten.
Wenn sich die Katz in den eigenen Schwanz beisst
Im nachfolgenden Beispiel beschreiben wir ein zu testendes System mit Lastverteilung. Dabei ist der Aufbau so konfiguriert, dass jeder Service doppelt vertreten ist und von den verfügbaren Lastverteilern die Arbeit zugeteilt bekommt.
Der Lastgenerator simulierte mehrere Clients. Im Backend sollte der Lastverteiler die Anfragen gleichmässig (round robbin) verteilen. Nachfolgende Grafik stellt die Messergebnisse der CPU-Auslastung der zwei Server dar.
Wie das Resultat zeigt kann bei der Performance Messung eine einseitige Lastverteilung festgestellt werden. Eine hohe Belastung bei Server 1 (blau) und keine bis kaum Belastung bei Server 2 (rot) oder andersherum. Idealerweise würden beide Server ähnlich hoch bei der eingezeichneten Ideallinie liegen, wenn sie gleichmässig ausgelastet wären.
In der Grafik sind die Berge und Täler der Kurve gut zu erkennen (siehe Pfeile). Während ein Server genug zu tun hat, dreht der andere Server „Däumchen“. Nach einer unbestimmten Zeit erhält der 2. Server die komplette Last, die der 1. Server zuvor bewältigen musste.
Der Grund für dieses Phänomen lag in der Konfiguration des Loadbalancers. Die Anforderungen besagten, dass der Loadbalancer jede Transaktion an einen der zwei Webserver verteilt. Stattdessen wird nach einer bestimmten Zeit die gesamte Kommunikation vom einen Server auf den anderen umgelenkt.
Spikes – Wandelnde Spitzen
Graphen mit Spitzenwerten / Ausreissern, die sonst gute Antwortzeiten haben, deuten auf ein nur teilweise performantes System hin. Wie im folgenden Bild zu sehen ist, zeigen sich Anwortzeiten von ungefähr 200ms. Dazwischen und zum Ende hin häufiger auftretend, erstrecken sich Spitzenwerte. Diese reichen in den Sekunden- oder sogar Minutenbereich hineinreichen.
Das System wurde mit mehreren Szenarien getestet, welche verschiedene Services angesprochen haben. Beim Performance Test sind die erstellten Szenarien parallel mit jeweils einer bestimmten Anzahl an Usern (Threads) ausgeführt worden. Dadurch sind die Messergebnisse aller Szenarien im Resultat erhalten. Das Ziel des Tests war es, die Gesamtleistung des Systems zu erhalten. Mit der Messung sind durch das Auftreten der Spitzen (siehe oberer Pfeil) Schwachstellen aufgetreten, die es nun einzugrenzen galt. Dabei wurden die betroffenen Anfragen (abgesetzte URLs) herausgefiltert und analysiert.
Die betroffenen Services wurden optimiert, so dass als neues Resultat in der Folgemessung ein gleichmässiger Verlauf des Messgraphen zu sehen war.
Gen Himmel ohne Wiederkehr
Ein gutes Beispiel für einen „Hitzkopf“ zeigt der folgende Graph. Der stetige und steile Anstieg des Graphen mit Auslauf ins Endlose und ohne Wiederkehr zeigen den „Knockout“ des Testsystems. Die Antwortzeiten steigen solange bis der Server gar keine Antwort mehr gibt.
Dieser Graph ist ein klarer Fall: Der Test war für das Testsystem zu fordernd. Für die Problemfindung werden die zuvor definierten Teilsysteme analysiert. Was zu Beginn mit End-To-End Test durchgeführt wurde, wird nun detailliert auf modularer Ebene erneut getestet und analysiert. Die detailliertere Analyse bringt einen erheblichen Mehraufwand mit sich, der mit dem Auftraggeber abgestimmt wird. Sehr oft ist dieser Aufwand im Detail nicht vorausplanbar..
Hinweis: Für die Analyse ist immer wieder zu kontrollieren, dass auch die entsprechende Anzahl an Testusern im richtigen Zeitrahmen ihre Anfragen versendet haben. Es war ebenfalls bei uns vorgekommen, dass die Testclients zu viele Anfragen gestellt haben, was nicht gefordert oder spezifiziert war.
Gimme more Load
Es gibt Situation, in denen die Last für das Testsystem nicht ausreicht. Das wirkt sich im Resultat als kaum erkennbare Veränderung an den niedrigen Antwortzeiten und der geringen Auslastung des Systems aus. Die nicht ausgenutzten Leistung der CPU und die geringfügige Verwendung von RAM und Festplatte verdeutlichen das.
Für das weitere Testen muss die Last erhöht werden. Dies wird mit der Erhöhung der Anzahl der anfragenden Threads beim Client erreicht. Dazu sind je nach Leistung des Client Rechners verteilte Systeme notwendig, die in der Gesamtheit die gewünschte Last erzeugen.
Performer
Um ein positives Resultat zu zeigen, gibt der folgende Graph ein mögliches Bild für ein performantes System.
Der Graph zeigt zu Beginn einen Anstieg, die Antwortzeiten bleiben jedoch im spezifizierten Bereich und sind somit als gut zu bewerten.
Fazit
Neben der Einhaltung der definierten Anforderungen (z.B. Antwortzeiten oder Transaktionsraten) steigen wir bei Bedarf tiefer in die Analyse der Messergebnisse ein, um Flaschenhälse zu finden. Wir vergleichen mehrere Diagramme untereinander und orientieren uns an Ausreissern oder ungewöhnlichem Verhalten der Systeme.
Für die Suche nach der Ursache von Performanceeinbrüchen können verschiedene Wege beschritten werden. Das ist von den Bedürfnissen des Kunden oder des Projektes, den jeweiligen Systemen und den Möglichkeiten der Analyse abhängig. Bei einem top-down-Ansatz wird das Gesamtsystem belastet und der Tester arbeitet sich Schritt für Schritt tiefer zu den einzelnen Komponenten vor. Stehen in einer frühen Phase eines Projektes nur einzelne Systemkomponenten zur Verfügung, bietet es sich an, diese „unter Strom“ zu setzen.
Die Abstimmung des Monitoring, clientseitig sowie serverseitig, muss stets gut bedacht und rechtzeitig definiert werden. Eine spätere Organisation des Monitoring ist in den meisten Fällen mit Mehraufwand verbunden. Das bringt Mehrkosten mit sich, da bestimmte Messungen erneut oder mehrmals durchgeführt werden müssen.
Wir, Niko und Hendrik, sind ein Teil des Performance-Test-Teams bei SwissQ. Mit Leistungstests befassen wir uns liebend gern und freuen uns auf jede neue Herausforderung.
| |
Hendrik Eichert | Niko Messerschmidt |