Lasttests mit JMeter

Aus THM-Wiki
Wechseln zu: Navigation, Suche

Überblick

Dieser Artikel behandelt die

und die

mit JMeter und dem Shell-Script performanceAnalyzer.sh, das für das Server-Monitoring zum Einsatz kommt. Für eine anschaulichere Erklärung der beiden Vorgänge sollen zwei Video-Tutorials dienen. Sie umfassen zum einen die Erstellung eines Testplans am Beispiel des Forums von eStudy mit allen relevanten Schritten und Testplan-Elementen (stellvertretend für alle Module von eStudy) und zum anderen die Durchführung eines Lasttests auf einem Test-Client und einem Test-Server.

Testplan-Erstellung

Video-Tutorial zur Testplan-Erstellung: http://homepages.fh-giessen.de/~hg12477/testplanerstellung.swf

In diesem Video wird anhand des Forums von eStudy exemplarisch gezeigt, wie sich unterschiedliche virtuelle Benutzer in eStudy einloggen können und zufällig ausgewählte Postings aufrufen. Dabei soll ein bestimmter Anteil der Benutzer außerdem jeweils auf ein Posting antworten, wobei ein weiterer Anteil dabei eine Datei hochlädt. Die Testergebnisse von JMeter werden dabei in einer Datei gespeichert. Dieses Szenario ist beispielhaft für alle weiteren Module von eStudy, für die auf die gleiche Weise Lasttests erstellt werden können.

Konfigurations-Elemente

Zu Beginn der Testplan-Erstellung ist es sinnvoll, einige globale Konfigurations-Elemente hinzuzufügen, auf die in einzelnen Testplan-Elementen Bezug genommen werden kann.

  • Name des Testplans

Der Name des Testplans wird im Wurzel-Element des Testplans festgelegt.

Testplan_Forum
  • Benutzerdefinierte Variablen (für Elemente des Testplans)

Mit Hilfe des Elements "Benutzerdefinierte Variablen" lassen sich eigene Variablen definieren, die in späteren Elementen des Testplans mit ${Variable} benutzt werden können. Die Variable "servername" ist der Name des Test-Servers.

servername: portal.mni.fh-giessen.de

Die Variable "path" enthält den Pfad zur Testumgebung (eStudy).

path: /benchmark/web/

Die Testdauer in Sekunden soll in der Variablen "test-duration" festgelegt werden.

test-duration: 3600

Die Variable "ramp-up-period" bestimmt, innerhalb welchen Zeitraums in Sekunden alle JMeter-Threads (virtuelle Benutzer) gestartet werden.

ramp-up-period: 120

Zur Verzögerung der hintereinander ausgeführten Requests sollen Timer benutzt werden. Der Timer "Gaussian Random Timer" enthält dabei zum einen eine feste Verzögerung (constant delay offset) und zum anderen eine zusätzlich hinzukommende zufällige Verzögerung (deviation).

timer-cdo: 3000
timer-dev: 10000

Die Variable "forum-threads" enthält die Anzahl der parallelen JMeter-Threads (virtuelle Benutzer).

forum-threads: 5

Im "jmeter-results-path" sollen die Ergebnisse des Tests auf dem Test-Client gespeichert werden.

jmeter-results-path: jmeter-results/Testplan_Forum/
  • HTTP Request Default Einstellungen

Mit diesem Element lassen sich Einstellungen vornehmen, die für alle Requests bzw. Sampler des Testplans gültig sein sollen.

Server Name oder IP: ${servername}
Port Number: 80
Protokoll: http
Path: leer lassen

Wenn alle Komponenten einer Webseite (Bilder, JavaScripts, Stylesheets, Flash, Sounds) bei jedem Request mitgeladen werden sollen, kann dies JMeter mitgeteilt werden.

Hole alle Bilder und Java Applets (nur HTML Dateien): aktiv
  • HTTP Cookie Manager

Der HTTP Cookie Manager ist notwendig, damit Cookies in JMeter gespeichert werden können.

keine weiteren Einstellungen notwendig
  • HTTP Header Manager

Im HTTP Header Manager lassen sich Request Headers von Browsern simulieren. In diesem Fall soll JMeter den Empfang Server-seitig komprimierter Dateien erlauben.

Accept-Encoding: gzip,deflate

HTTP Proxy Server

Der HTTP Proxy Server wird als Non-Test Element der Workbench des Testplans hinzugefügt, um Requests des Browsers automatisch in JMeter aufzuzeichnen und im Testplan umzusetzen. Damit lässt sich bei der Erstellung der Testpläne viel Zeit einsparen. Allerdings müssen die aufgezeichneten Requests meist noch von Hand angepasst werden.

Port: 8080
Target Controller: forum > browse forum
Capture HTTP Headers: inaktiv
URL Muster zum einschliessen: .*\.php.*, .*\.html
URL Muster zum ausschliessen: .*userdate\.php
  • Start des HTTP Proxy Servers und automatisches Aufzeichnen der Requests des Browsers

Nach dem Betätigen des Start-Buttons im HTTP Proxy Server von JMeter, werden alle (bis auf HTTPS) Requests des Browsers in JMeter aufgezeichnet und in Elemente des Testplans umgesetzt. Dafür muss der Browser so konfiguriert werden, dass er für den Proxy den Port 8080 (beliebig) benutzt. Um nicht jedesmal von Hand die Verbindungseinstellungen des Browsers ändern zu müssen, kann zum Beispiel auf das Firefox-Addon Switchproxy(zu diesem Zeitpunkt noch nicht für Firefox 3 erhältlich) zurückgegriffen werden. Die Aufzeichnung wird durch das Betätigen des Stop-Buttons im HTTP Proxy Server beendet.

Thread Gruppe

Eine Thread Gruppe dient in JMeter dazu, mehrere Threads gleichzeitig ausführen zu können. Dabei können die Anzahl der Threads, ihre zeitliche Verzögerung beim Start des Tests und auch die Testdauer festgelegt werden.

Name: forum
Anzahl von Threads: ${forum-threads}
Ramp-Up Period (in seconds): ${ramp-up-period}
endlos wiederholen: aktiv
Scheduler: aktiv
Duration (seconds): ${test-duration}

Einfacher Controller

Mit Hilfe eines einfachen Controllers in einer Thread-Gruppe lassen sich HTTP Request Sampler zu einer Einheit zusammenfassen. Im weiteren Verlauf der Testplan-Erstellung: Mit Hilfe eines Wiederholungs-Controllers können Sampler außerdem mehrmals durchlaufen werden. Mit einem Durchsatz-Controller lässt sich steuern, wie viel Prozent der ausgeführten Requests auf den Controller entfallen sollen.

Name: browse forum

Login mit HTTPS

Da JMeter mit dem HTTP Proxy Server keine Daten aus verschlüsselten HTTPS-Formularen aufzeichnen kann, muss der Login von Hand erstellt werden. Dabei soll außerdem eine CVS-Datei mit den Spalten Benutzername und Passwort verwendet werden, um viele unterschiedliche virtuelle Benutzer während des Tests Aktionen ausführen zu lassen.

CSV Data Set Config

Dieses Element wird der Thread Gruppe "forum" hinzugefügt, um die Login-Daten aus der CSV-Datei zu lesen:

Name: Logindaten-Student
Filename: TESTDATA.studentlogin.csv
Variable Names (comma-delimited): username,password
Delimiter: ,
Recycle on EOF: true
Stop thread on EOF: false

HTTP Request Sampler (für den Login)

Der HTTP Request Sampler wird dem einfachen Controller forum hinzugefügt, um den Login mit den Login-Daten aus der CSV-Datei durchzuführen. Die Umstellung des Protokolls auf HTTPS und auf die Portnummer 443 muss dabei explizit vorgenommen werden.

Name: login
Protokoll: https
Port Number: 443
Method: POST
Path: ${path}login.php
Folge Redirects: aktiv
Benutze KeepAlive: aktiv
Parameter, die mit dem Request gesendet werden: 
 username: ${username}
 password: ${password}
 okButton: Einloggen

Listener

In JMeter werden Listener benutzt, um die bei einem Lasttest anfallenden Daten aufzuzeichnen, darzustellen und abzuspeichern.

  • View Results Tree

Dieser Listener wird in diesem Fall nur für das Debugging des Testplans verwendet und wird dem Wurzel-Element "Testplan_Forum" hinzugefügt. Neben der Anzeige von Response Assertions und des Request-Textes lassen sich die mit den Requests aufgerufenen Seiten auch als HTML rendern.

  • Simple Data Writer

Dieser einfachste aller Listener wird dem Testplan hinzugefügt, um die beim Lasttest (über die Konsole) anfallenden Daten in einer Datei zu speichern. Da bei einem Lasttest über die Konsole keine graphischen Darstellungen möglich sind, wird nur dieser Listener während der späteren Tests verwendet.

Dateiname: ${jmeter-results-path}SimpleDataWriter.jtl

Response Assertion

Response Assertions werden allen HTTP Request Samplern hinzugefügt, um sicherzustellen, dass diese korrekt ausgeführt wurden (Ergebnis true oder false). Damit kann beispielsweise überprüft werden, ob eine angeforderte Webseite ein bestimmtes Wort enthält oder der Response Code wie erwartet ausfällt.

Timer

Timer werden den Samplern hinzugefügt, um diese mit einer einstellbaren Verzögerung zu starten. Damit wird zum einen eine Überlastung des Test-Servers durch die gleichzeitige Ausführung aller Requests vermieden. Zum anderen lassen sich damit auch Zufallszeiten für die Ausführung der Sampler einbringen. In diesem Fall wird der Gaussian Random Timer benutzt:

Deviation (in milliseconds): ${timer-dev}
Constant Delay Offset (in milliseconds): ${timer-cdo}

HTML Link Parser (Pre Processor)

Der HTML Link Parser wird dem HTTP Request Sampler für die Anzeige eines zufälligen Forum-Postings hinzugefügt. Durch den HTML Link Parser lassen sich alle Links auf einer Webseite parsen. Dadurch ist es mit einem regulären Ausdruck als Argument eines Samplers beispielsweise möglich, einen Link zufällig auszuwählen. So kann ein zufälliges Posting in einem Board des Forums aufgerufen werden:

Path: ${path}forum/showtopic.php
threadid: .*

Regular Expression Extractor (Post Processor)

Der Regular Expression Extractor wird ebenfalls dem HTTP Request Sampler für die Anzeige eines Forum-Postings hinzugefügt. Dadurch lässt sich beispielsweise Text aus der aufgerufenen Webseite oder auch der URL extrahieren (gewöhnlich mit dem regulären Ausdruck ".+?"). Dies dient in diesem Fall dazu, die Thread-ID eines zufällig aufgerufenen Postings im Forum zu extrahieren und in einer Variable ("Reference Name") zu speichern, um einen virtuellen Benutzer auf dieses Posting antworten lassen zu können.

Reference Name: threadid
Regular Expression: <input type="hidden" name="thread\[threadid\]" value="(.+?)"/>
Template: $1$
Match No. (0 for Random): 1

Die Variable ${threadid} kann nun in weiteren Samplern benutzt werden.

Test-Durchführung

Video-Tutorial zur Test-Durchführung: http://homepages.fh-giessen.de/~hg12477/testdurchfuehrung.swf

Die Durchführung der Lasttests erfordert mehrere einzelne Schritte, die jedesmal in einer festgelegten Reihenfolge ausgeführt werden. Damit soll zum einen die Reproduzierbarkeit der Tests sichergestellt werden und zum anderen erleichtert ein systematischer Ablauf die Durchführung der Performance-Tests. (Dieser Ablauf ließe sich teilweise automatisieren mit einem Shell-Script oder auch Ant).

  • Einspielen des Datenbank-Dumps

Der für die Tests erstellte Datenbank-Dump wird vor der Ausführung jedes Tests auf dem Test-Server neu eingespielt, um die Testdaten in der Datenbank in einen definierten Zustand zu bringen. Damit wird sichergestellt, dass jeder Test die gleichen Daten benutzt und damit reproduzierbar ist. Der Import in MySQL wird wie folgt durchgeführt:

user@testserver:~$ mysql -u<user> -p
mysql> use estudy;
mysql> source testdump.sql;
  • Neustart von MySQL und Apache/Lighty

MySQL und Apache werden neu gestartet, um eventuelle Änderungen der Konfiguration zu übernehmen und von einem definierten Zustand auszugehen.

user@testserver:~$ sudo /etc/init.d/mysql restart
user@testserver:~$ sudo /etc/init.d/apache2 restart
  • Start von performanceAnalyzer.sh

Das Skript performanceAnalyzer.sh wird auf dem Test-Server zum Monitoring des Systems unter Last gestartet. Dabei werden alle anfallenden Ergebnisse in einer Log-Datei für die spätere Auswertung gespeichert:

user@testserver:~$ nohup sudo nice -n -10 ./performanceAnalyzer.sh > performanceAnalyzer.log
  • Start von JMeter

JMeter wird auf dem Test-Client gestartet:

user@testclient:~$ nohup java -Xmx512m -Xms256m -jar ApacheJMeter.jar -n -t Testplan.jmx -p jmeter.properties 2>&1

JMeter beendet sich nach Ablauf der eingestellten Test-Dauer von alleine.

  • Abholen der Test-Ergebnisse und Bereinigung

Der Performance-Analyzer muss auf dem Test-Server manuell gestoppt werden. Dies geschieht mit folgendem Befehl:

user@testserver:~$ sudo killall performanceAnalyzer.sh

Die Log-Datei performanceAnalyzer.log mit den Ergebnissen des Monitorings wird zur späteren Analyse auf den eigenen Arbeitsrechner heruntergeladen. Dies kann zum Beispiel mit dem Programm WinSCP geschehen, das es ermöglicht, sich per SSH auf dem Test-Server einzuloggen und die entsprechenden Dateien über das Secure Copy Protokoll zu übertragen. Anschliessend wird die Datei performanceAnalyzer.log auf dem Test-Server manuell gelöscht.

Die Ausführung von JMeter erzeugt drei Dateien: SimpleDataWriter.jtl, jmeter.log und nohup.out. SimpleDataWriter.jtl enthält die während des Tests aufgezeichneten Daten, während jmeter.log Informationen über den Ablauf des Tests enthält. Dies sind im allgemeinen Status- und Fehlermeldungen. Die dritte Datei, nohup.out, enthält alle Meldungen, die normalerweise auf der Standardausgabe ausgegeben werden. Sie wird automatisch beim Aufruf von nohup erzeugt. Nach dem Herunterladen der Ergebisse von JMeter sollten diese für weitere Testläufe ebenfalls gelöscht werden.

Auswertung der Testergebnisse

Synchronisation der Test-Ergebnisse von JMeter und performanceAnalyzer.sh

Zur Auswertung der mit JMeter und dem Shell-Skript performanceAnalyzer.sh gesammelten Daten müssen diese zeitlich synchronisiert werden. Dazu können beispielsweise mit Hilfe von phpMyAdmin die Inhalte beider Dateien

  • SimpleDataWriter.jtl (bzw. Testplan_Forum.jtl)
  • performanceAnalyzer.log

in jeweils eine Datenbanktabelle importiert und anschliessend mit einem JOIN über den Zeitstempel zu einer einzigen Ergebnismenge verschmolzen werden. Das dabei verwendete SQL-Statement hat folgende Form:

SELECT * FROM jmeter, pa where pa.time = jmeter.timeStamp

Das dabei gewonnene Ergebnis lässt sich in phpMyAdmin zur weiteren Analyse als "CSV-Daten für MS Excel" exportieren und in Excel importieren (falls gewünscht).

Falls keine Synchronisation der beiden Dateien nötig ist, kann die Ergebnisdatei "SimpleDataWriter.jtl" auch direkt in einem Listener (zum Beispiel "Summary Report") in JMeter analysiert werden.

Hinweise zu performanceAnalyzer.sh

Dieses Shell-Script dient zum Monitoring des Test-Servers. Es verwendet dabei einige UNIX-Kommandos, die unter anderem die Speicherauslastung, die CPU-Belastung, die aktuelle Anzahl von Connections zum Webserver und zum MySQL-Server aufzeichnet: Es kommen dabei die Programme vmstat, netstat und mysql zum Einsatz. Pro Sekunde wird eine Zeile mit Daten erzeugt, die folgendes Format hat:

time,r,b,swpd,free,buff,cache,si,so,bi,bo,in,cs,us,sy,id,wa,ce,sr,ss,bs,br,tc

Die einzelnen Spalten enthalten dabei folgende Informationen:

Procs
r: The number of processes waiting for run time. (Wichtig für CPU-Auslastung!)
b: The number of processes in uninterruptible sleep.
Memory
swpd: the amount of virtual memory used. (Wichtig, falls Swapping auftritt!)
free: the amount of idle memory.
buff: the amount of memory used as buffers.
cache: the amount of memory used as cache.
Swap
si: Amount of memory swapped in from disk.
so: Amount of memory swapped to disk.
IO
bi: Blocks received from a block device.
bo: Blocks sent to a block device.
System
in: The number of interrupts per second, including the clock.
cs: The number of context switches per second.
CPU
us: Time spent running non-kernel code. 
sy: Time spent running kernel code. 
id: Time spent idle, this includes IO-wait time. (Wichtig für die prozentuale Auslastung der CPU!)
wa: Time spent waiting for IO..
Network
ce: connections established (Wichtig für die Anzahl der Connections zu Apache/Lighty!)
sr: segments received
ss: segments send out
MySQL
bs: bytes sent
br: bytes read
tc: threads connected (Wichtig für die Anzahl der Connections zum MySQL-Server!)

Hinweise zur Datei jmeter.properties

In der Property-Datei von JMeter müssen im Grunde keine Umstellungen vorgenommen werden. Dies betrifft vor allem die Einstellungen für das Zertifikat für den HTTPS-Login. JMeter akzeptiert auch ohne zusätzliche Konfiguration Zertifikate.

Da performanceAnalyzer.sh für den Zeitstempel das Format hh:mm:ss verwendet, ist es jedoch sinnvoll, den Zeitstempel für die Listener von JMeter ebenfalls auf hh:mm:ss umzustellen, falls die Ergebnisdateien von JMeter und performanceAnalyzer.log später synchronisiert werden sollen. Dies ist in der Property-Datei von JMeter in folgendem Abschnitt möglich:

# Timestamp format
jmeter.save.saveservice.timestamp_format=HH:mm:ss

Weblinks

Dateien