Lasttests mit dem Werkzeug Gatling

Erfahrungsbericht eines LoadRunner Lasttesters

Gatling - Ein Erfahrungsbericht eines LoadRunner Lasttesters
 
von Stephan Dannewitz | QMETHODS | August 2017
 

Motivation für den Review von Gatling

QMETHODS führt seit über 17 Jahren Lasttests für Kunden in Softwareentwicklungs- und IT-Projekten durch. Auf Grund der großen Spannbreite an eingesetzten Technologien wie HTTP, WebServices, Java, RMI, SQL, RDP, Citrix etc. kommt meist das Lasttest-Werkzeug LoadRunner zum Einsatz.
Als Lasttester kommt man an dem Werkzeug Gatling (Wortbedeutung: automatische Schusswaffe) nicht vorbei. Mich hat in erster Linie der Non-Blocking-I/O gereizt mir das Lasttest-Werkzeug genauer anzuschauen.
 

Automation von Geschäftsprozessen in Gatling

Gatling - Ein Erfahrungsbericht eines LoadRunner Lasttesters Für die Erstellung eines aussagekräftigen Lasttests ist die technische Abbildung von Geschäftsprozesse notwendig. In Gatling werden die Geschäftsprozesse als 'Szenario' bezeichnet. Diese Szenarien können aus mehreren Aktionen bestehen, die wiederum innerhalb von Objekten (als Methoden) implementiert und beliebig kombiniert werden können. Die Unterteilung in Objekte und deren Methoden ist nicht zwangsläufig notwendig, wird aber aufgrund der Übersichtlichkeit empfohlen.
Als Beispiel nutzen wir unsere lokale Atlassian Jira Plattform. Hierbei wird die Startseite von Jira aufgerufen, die Benutzeranmeldung durchgeführt, nach dem Begriff 'Gatling' gesucht und abschließend der Benutzer wieder von Jira abgemeldet.
Das Szenario erhält den Namen 'Beispiel_Jira' und ruft die Methoden ('Login', 'Search' etc.) aus dem Objekt 'Jira' auf. Ein zusätzliches Szenario 'Beispiel_Jira_Peak' dient zur Erzeugung einer kurzzeitigen Peak-Last. Durch die Angabe der Laufzeit im Szenario ist leider die Wiederverwendung von Szenarien eingeschränkt. Diese wäre besser in der Konfiguration der Simulation aufgehoben.
 
val scn1 = scenario("Beispiel_Jira").during(3 minutes){ 
exec(Jira.GoTo).exec(Jira.Login).exec(Jira.Search).exec(Jira.Logout)} 

val scn2 = scenario("Beispiel_Jira_Peak").during(60 seconds){ 
exec(Jira.GoTo).exec(Jira.Login).exec(Jira.Search).exec(Jira.Logout)} 
Code-Beispiel: Zusammenstellung von Szenarien auf Basis der Aktionen
 
Die Implementierung eines Prozessschrittes ist recht selbsterklärend, wie das folgende Code-Beispiel anhand des Jira-Logins zeigt:
  • Ausführung eines POST-Request inklusive der Parameter für Benutzernamen und Passwort 
  • Prüfung auf Existenz eines Tokens im Response-Cookie 
  • Speicherung des Tokens in der Variable 'Token' zur späteren Nutzung 
  • Prüfung auf eine erfolgreiche serverseitige Ausführung 
  • Pausieren des Skriptes für 1 Sekunde 
object Jira {
 val Login = {
 group("Login_Group"){
 exec(http("Login")
 .post("/rest/gadget/1.0/login")
 .formParam("os_username", "Username")
 .formParam("os_password", "Password")
 .check(headerRegExp("Set-Cookie", "atlassian.xsrf.token=(.*?);")
 .find.saveAs("Token"))
 .check(status.is(200)))}
 .pause(1)
 }
...
}
Code-Beispiel: Objekt, Methoden und Szenario in Gatling definieren
 
Die Server-Response enthält in diesem Fall Cookies, in denen die SessionID und das Token enthalten sind. Gatling übernimmt automatisch für jeden VUser (virtueller Benutzer) das Cookie-Management. Daher ist hier kein Korrelieren notwendig.
Noch ein weiteres Beispiel: Um sicherzustellen, dass die Methode 'Search' erfolgreich war, lässt sich mit 'checks' der Inhalt der Seite hinsichtlich der Suchergebnisse überprüfen. In diesem Fall wird nach einem spezifischen Jira-Vorgang gesucht, der nur nach erfolgreichem Login und erfolgreicher Suche angezeigt wird.
.exec(http("Suche verifizieren") 
.get("/browse/QI-627?jql=text%20~%20%22gatling") 
.check(RegExp("Gatling Blogeintrag erarbeiten")))
Code-Beispiel: Verifizierung einer Aktion mittels RegExp
 
Dynamische Daten aus der Anwendung können manuell mittels RegExp erfasst, in einer Variable gespeichert und an beliebiger Stelle wiederverwendet werden.
<!-- Das xsrf-Token wird während des Logins aus dem gesetzten Cookie extrahiert 
und in der Variable "Token" gespeichert -->

.check(headerRegExp("Set-Cookie", "atlassian.xsrf.token=(.*?);").find.saveAs("Token"))

<!-- Im Logout-Prozess muss das Token an die URL angehängt werden -->

val Logout = {
group("Logout"){
exec(http("Logout")
.get("/secure/Logout!default.jspa?atl_token="+"${Token}")}
Code-Beispiel: Korrelation dynamischer Daten
 

Erstellung und Durchführung einer Lasttest-Simulation mit Gatling

Nach erfolgreicher Automation der Geschäftsprozesse in Form von Szenarien ist das Ausführungsverhalten dieser zu definieren. Dieses wird bei Gatling als Simulation bezeichnet. Es können die Anzahl der Benutzer, das Anlaufverhalten (Ramp-up), die maximale Laufzeit und viele weitere Parameter definiert werden:
Detaillierte Parameterliste für die Definition des Lastverhaltens
 
In unserem Beispiel habe ich die erste Simulation wie folgt definiert: 5 Benutzer starten über einen Zeitraum von 10 Sekunden und führen das Szenario über 3 Minuten immer wieder von vorn durch (Achtung: Die 3 Minuten sind im obigen Szenario definiert worden). In der zweiten Simulation wird nach 60 Sekunden eine Peak-Last mit 25 weiteren Benutzern über 60 Sekunden erzeugt.
setUp(
scn1.inject(rampUsers(5) over(10 seconds)),
scn2.inject(nothingFor(60 seconds), atOnceUsers(25))
).protocols(httpProtocol)
Code-Beispiel: Konfiguration der Gatling Simulation
 
Während der Ausführung einer Lasttests werden dem Benutzer über die Konsole zyklisch Basisinformationen über den Ausführungsstatus ausgegeben. Mh, das war mir dann doch etwas zu rudimentär!
Gatling - Ein Erfahrungsbericht eines LoadRunner Lasttesters
Abbildung: Ausgabe zum Status des Lasttests in der Konsole
 
Für ein übersichtliches Live-Monitoring bietet Gatling die hauseigene, kostenpflichtige Erweiterung "Gatling Frontline" an.
Gatling Frontline
 

Analyse der Ergebnisse des Gatling Lasttests

Nach erfolgreicher Durchführung des Lasttests generiert Gatling ein HTML-Dokument mit den Testergebnissen. Hier ist eine begrenzte Anzahl an Grafiken und Tabellen fest vordefiniert, die jedoch nicht projektspezifisch erweiterbar sind. Einige Beispiele sind im Folgenden erläutert.
Folgende Abbildung visualisiert noch einmal das in der Simulation konfigurierte Verhalten hinsichtlich der Benutzer und kann helfen entsprechende Fehlkonfigurationen zu erkennen.
Gatling - Ein Erfahrungsbericht eines LoadRunner Lasttesters
Abbildung: Anzahl der von Gatling simulierten Benutzer über den Lasttest-Zeitraum
 
Der Klassiker ist natürlich die tabellarische Übersicht über die Anzahl der Aufrufe und deren Antwortzeiten zzgl. entsprechender Statistiken. Es ist sehr empfehlenswert in den Szenarien die Group-Funktion zu verwenden, um die einzelnen Anfragen einem Funktionsaufruf zuordnen zu können.
Gatling - Ein Erfahrungsbericht eines LoadRunner Lasttesters
Abbildung: Anzahl der von Gatling ausgeführten Aufrufe und Antwortzeiten gruppiert nach den Szenarien
 
Eine Visualisierung der Antwortzeiten mithilfe von Perzentilen ermöglicht die Bewertung des Laufzeitverhaltens der Anwendung. Folgende Abbildung zeigt den deutlichen Anstieg der Antwortzeit im Peak-Zeitraum. Hier ist wieder die Group-Funktion wichtig, um auch auf Funktionsebene eine Bewertung durchführen zu können.
Gatling - Ein Erfahrungsbericht eines LoadRunner Lasttesters
Abbildung: Antwortzeiten des Gatling-Lasttests visualisiert mit Perzentilen
 

Mein Fazit zu Gatling

Mit meinen LoadRunner-Erfahrungen konnte ich einen exemplarischen Lasttest zügig umsetzen. Die in Gatling verwendete Begriffswelt mit Szenario und Simulation hat bei der Diskussion mit meinem Kollegen allerdings öfters zu Missverständnissen geführt.
Sehr positiv ist mir aufgefallen, dass alle Lasttest-Artefakte in Form von Szenarien und Simulationen in einem Skript abgelegt sind. Dies ist eine gute Voraussetzung für die Versionierung im Entwicklungs-Branch und die Integration in den Testautomationsbereich des DevOps-Prozesses.
Gatling kann im direkten Vergleich zu LoadRunner dank integrierter Non-Blocking-Technologie ein Vielfaches an Last von einem Rechner aus erzeugen. Dies ist beim LoadRunner erst unter Verwendung von mehreren Lasttreibern möglich. Gatling bietet dafür keine Out-of-the-Box-Lösung für die Lastverteilung auf mehrere Rechner an.
Zur Verbesserung der Übersicht und Wiederverwendbarkeit ist ein Refactoring der mit der GUI aufgezeichneten Skripte allerdings unerlässlich. Dieser zeitliche Mehraufwand ist nicht zu unterschätzen und bringt einige Fallstricke mit sich.
Das fehlende Live-Dashboard während der Lasttest-Durchführung erschwert die Interpretation über den Status des Lasttests (Anzahl Benutzer, Antwortzeiten, Ressourcenverbrauch etc.). Da fühle ich mich beim LoadRunner mit dem Zugang zu allen benötigten Informationen sicherer im Sattel!
Die Darstellung der Testergebnisse und die Analysemöglichkeiten fallen im Vergleich zu LoadRunner etwas mau aus. In puncto Analysierbarkeit und Benutzerfreundlichkeit kann Gatling dem LoadRunner somit nicht das Wasser reichen.
Trotz der Kritikpunkte ist Gatling ein mächtiges Open-Source-Werkzeug und kann besonders mit der Erzeugung von hohen Lasten dank Non-Blocking-Technologie punkten!

Was ich positiv finde

  • Hohe Anzahl an zu simulierenden Benutzern mittels Non-Blocking-Technologie. 
  • All-in-One Skript mit Szenarien und Simulation für einfache Handhabung und DevOps-Integration. 
  • Einfache Installation unter Linux und Windows. 
  • Kostenfreie Open-Source-Lösung. 

Wo ich Möglichkeiten zur Verbesserung sehe

  • Schwieriger Einstieg für Neulinge im Bereich Lasttest mangels Benutzerführung durch GUI. 
  • Keine werkzeugbasierte Unterstützung für die Korrelation der Szenarien bzw. Analyse der Lauffähigkeit dieser (vgl. Wizards im LoadRunner). 
  • Live-Monitoring während der Durchführung des Lasttests nur mit kostenpflichtiger Erweiterung "Gatling FrontLine" möglich. 
  • Keine Möglichkeit zur Verteilung der Testausführung auf mehrere Lasttreiber. 
  • Die Ausgabe der Testergebnisse basiert auf einem nicht anpassbaren bzw. erweiterbaren HTML-Report, was die Analyse und Auswertung erschwert. 
  • Im Szenario muss bereits die Ausführungsdauer angegeben werden. Diese wäre besser in der Simulation zu definieren, um die Wiederverwendbarkeit der Szenarien zu erhöhen. 
  • Keine Möglichkeit ein Herunterfahren (Ramp-down) der virtuellen Benutzer in der Simulation zu definieren. 
  • Durch die noch kleine Community und die teilweise spärliche Dokumentation ist es schwierig, auf komplexe Fragen oder technische Details Antworten zu finden. 
 
In unserem QMETHODS-GitHub finden Sie das vollständige Gatling-Lasttest-Skript sowie einen Lasttest-Ergebnisreport im HTML-Format zum Herunterladen.
QMETHODS Github
 
Gatling Webseite
Gatling Frontline - kostenpflichtige Erweiterung für Live-Dashboards
Begriff Gatling (Wikipedia)