Performance testing med open source værktøjet JMeter

Denne tutorial om performance testing med open source værktøjet JMeter, er den første i en serie af indlæg omkring brugbare værktøjer til open source udvikling. Materialet er udarbejdet af Andreas Kring, der introducerede JMeter ved en af Magentas udviklerdage. Her gav Andreas en workshop om sit arbejde med værktøjet til at teste ydeevnen for systemer baseret på frameworket Alfresco. Materialet er delt op i 3 øvelser, der når omkring mange af de fundamentale konfigurationsmuligheder for JMeter.

Installation af JMeter

Performance testing er en vigtig del af softwareudvikling og der findes en række værktøjer til dette. Heriblandt open source værktøjet JMeter, der kræver Java 8+ så installér først Java, hvis du ikke allerede har denne installeret (på Ubuntu 18.04 LTS køres eksempelvis):

$ sudo apt install openjdk-11-jdk

Derefter kan JMeter hentes på https://jmeter.apache.org/download_jmeter.cgi. Hent .tgz filen og udpak denne – derefter burde JMeter være klar til kørsel fra mappen bin/jmeter.

For at få en lidt højere tidsopløsning på de grafer, som JMeter genererer, skal vi lige skrue lidt på en enkelt konfiguration. I filen bin/reportgenerator.properties ændres nedenstående property til 5000 i stedet for 60000:

jmeter.reportgenerator.overall_granularity=5000

Installering af Docker

Nedenstående applikationer kører i Docker, så hvis du ikke allerede har Docker installeret, så gør dette vha. instruktionerne her.

Øvelse 1 – oprettelse af JMeter testplan

Dette er en JMeter “Hello world” øvelse, hvor vi skal lave en Test Plan indeholdende en Thread Group, som indeholder en Simple Controller, der indeholder et enkelt Request.

Formålet er at undersøge to funktionelt identiske REST services, hvor den ene er udviklet i Python, mens den anden er skrevet i Java. De to REST services startes op på følgende måde:

Python

En Flask-applikation, som kan deployes med Docker:

$ cd docker/flask
$ docker build -t flask-app .
$ docker run --name flask-app -p 5000:5000 flask-app

Der skulle nu køre en Flask app på port 5000. App’en returnerer det n’te Fibonacci-tal vha. en rekursiv funktion (valgt bevidst, da dette går langsomt for store værdier af n). Test, at app’en fungerer ved at kalde fx:

$ curl http://localhost:5000/fib?n=7

som vil returnere det 7. Fibonacci-tal.

Java

En Spring Boot applikation, som enten kan deployes direkte med Java eller også via en Docker container på samme måde som ovenfor. Deployment direkte med Java foretages således:

$ cd docker/spring-boot
$ java -jar target/performance-testing-workshop-0.0.1-SNAPSHOT.jar

Med Docker klares det ved:

$ cd docker/spring-boot
$ docker build -t spring-boot-app .
$ docker run --name spring-boot-app -p 8080:8080 spring-boot-app

App’en kan testes ved at kalde fx:

$ curl http://localhost:8080/fib?n=7

JMeter

Start JMeter og gør følgende:

  1. Tilføj en Thread Group til testplanen.
  2. Tilføj en Simple Controller til trådgruppen.
  3. Tilføj et HTTP Request til controlleren og udfyld felterne efter behov.
  4. Tilføj et View Results Tree til trådgruppen.
  5. Klik på View Results Tree til højre og kør testplanen (vha. den grønne play-knap).
  6. Verificér, at kaldet gik godt og at de forventede data blev returneret.
  7. Tilføj en Timer til requestet og vælg en passende “think time”.
  8. Tryk på Thread Group og øg antallet af brugere. Vælg også en passende Ramp-up periode.
  9. Sæt Loop-Count til uendelig og sæt en Duration på fx 200 s.
  10. Gem testplanen og kør denne fra kommandolinjen med
    $ jmeter -n -t sti/til/testplan.jmx -l log.jtl
  11. Generér en testrapport med
    $ jmeter -g log.jtl -o report
    og kig på resultatet i en browser.
  12. Undersøg, hvilken af de to REST applikationer, som performer bedst (definér selv passende parametre for at afgøre dette – inkl. værdien af n, som fodres ind i Fibonacci-funktionen).

Et eksempel på en testplan, som kan bruges sammenligning, kan findes i mappen jmeter/ex1.jmx.

Øvelse 2 – kald til et Alfresco-system

Opsætning af en testplan, som indeholder lidt flere elementer. Vi laver nogle kald mod et standard Alfresco-system (leveres i Docker). Testplanen skal indeholde følgende elementer:

  1. Et Config Element, som læser en række brugere fra en CSV-fil.
  2. En setUp Thread Group (der kun køres en enkelt gang), som opretter brugerne fra CSV-filen i Alfresco.
  3. En trådgruppe indeholdende requests, der:
    • Uploader et dokument med et tilfældigt navn (for at filnavne ikke skal konflikte, når man brugere uploader filer samtidigt).
    • Henter dokumentet igen.
    • Sletter dokumentet.

Alfresco endpoints

Her følger en kort beskrivelse af de endpoints, vi får brug for at kalde i testplanen. Ved POST requestene er der i hvert tilfælde givet et eksempel på det JSON, der skal sendes.

Oprettelse af brugere

POST /alfresco/s/api/people
{
  "userName": "username",
  "firstName": "firstname",
  "lastName": "lastname",
  "email": "username@example.org",
  "password": "secret"
}

Tilføje brugere til et Alfresco site

Brugerne skal tilføjes til et site i Alfresco. Vi anvender Alfrescos standard site, som har site short name, som er swsdp. For at tilføje en bruger til dette site kaldes:

POST /alfresco/s/api/sites/swsdp/memberships
{
  "role": "SiteManager",
  "person": {
  	"userName":"username"
  }
}

Upload af dokument

Foretages vha. et multipart/form-data POST request til

POST /alfresco/s/api/upload

hvor e.g. følgende felter sendes med i formen:

siteid=swsdp
containerid=documentLibrary
filename=someFile.txt
filedata=(binary <- selve filen)

Hente et dokument

GET /alfresco/s/api/node/content/workspace/SpacesStore/${nodeRef}

hvor ${nodeRef} er referencen til den Alfresco node, hvor filen er gemt. Bemærk, at denne NodeRef returneres i ovenstående kald, hvor filen blev uploadet.

Slette et dokument

DELETE /alfresco/api/-default-/public/alfresco/versions/1/nodes/${nodeRef}

hvor ${nodeRef} på samme måde som før er referencen til den Alfresco node, hvor filen er gemt.

Testplanen

Gør nedenstående for at konstruere JMeter testplanen.

CSV-filen med brugere

Hent CSV-filen med brugere her.

Oprettelse af setUp Thread Group

  1. Start Alfresco:
    $ cd docker/alfresco $ docker-compose up
    Alfresco lytter nu på port 8080 på localhost.
  2. Lav en ny JMeter testplan og sæt flueben ved feltet
    Run Thread Groups consecutively.
  3. Tilføj et HTTP Request Defaults element (findes under Config Elements) til testplanen, og sæt værdierne for
    Server Name og Port Number.
  4. Tilføj en CSV Data Set Config (også et Config Element) og brug denne til at indlæse bruger og passwords fra CSV-filen (udfyld felterne Filename og Variable Names).
  5. Tilføj et View Results Tree til testplanen (findes under Samplers).
  6. Opret en setUp Thread Group, som skal oprette brugerne i CSV-filen og sæt Loop Count feltet i denne til 50 (da der er 50 brugere i CSV-filen).
  7. Tilføj en Simple Controller til ovenstående trådgruppe (findes under Logic Controllers).
  8. Tilføj en HTTP Authorization Manager til controlleren og udfyld felterne
    Base URL=http://localhost:8080), Username=admin og Password=admin.
  9. Tilføj en HTTP Header Manager til controlleren og tilføj headeren
    Content-Type: application/json
    til denne.
  10. Tilføj et HTTP Request til controlleren, som opretter en bruger via informationer i CSV-filen.
  11. Tilføj et HTTP Request til controlleren, som tilføjer brugeren til swsdp sitet i Alfresco.

Verificér, at testplanen fungerer indtil videre før vi går videre performance testing med JMeter af Alfresco.

Oprettelse af load test trådgruppen

  1. Tilføj en ny trådgruppe til testplanen (passende konfigrationsværdier for denne udfyldes senere, når vi har verificeret, at det hele fungerer som det skal).
  2. Tilføj en Simple Controller til trådgruppen.
  3. Tilføj en HTTP Authorization Manager til controlleren (på samme måde som før, men brug i stedet brugerne fra CSV-filen til at autentificere med denne gang i stedet for admin-brugeren.
  4. Tilføj et HTTP request til at uploade et dokument til Alfrescos swsdp site, idet følg. skal huskes:
    • Sæt flueben ved feltet Use multipart/form-data
    • Under Parameters sættes felterne siteid, containerid og filename. Et tilfældigt filnavn kan genereres med JMeter funktionen ${__RandomString(20,abcdefghijklmnopqrstuvxyz,randomFilename)}.doc, som genererer en tilfældig streng, der er 20 karakterer lang (valgt fra listen af de anførte bogstaver). Værdien af strengen gemmes efterfølgende i JMeter variablen randomFilename, som vi kan referere til senere.
  5. Tilføj til requestet en Regular Expression Extractor (findes under Post Processors) og tilføj et regex, som ekstraherer NodeRef’en fra responset på requestet. Vælg et passende variablenavn, hvor den udtrukne værdi kan gemmes.
  6. Tilføj en Gaussian Random Timer (findes under Timers) til requestet og sæt en passende “think time”.
  7. Tilføj et HTTP Request til controlleren, som henter det netop uploadede dokument vha. variablen fra upload requestst.
  8. Tilføj et HTTP Request til controlleren, som sletter det uploadede dokument igen.
  9. Tilføj også passende timere til de to sidste requests.

Test af trådgruppen

Test, at kaldene i trådgruppen, fungerer (du kan evt. deaktivere setUp trådgruppen om nødvendigt).

Performance test Alfresco

Vælg passende parametre for selve “load” trådgruppen. Kør herefter en række test for at finde ud af, hvor mange samtidige brugere Alfresco kan klare i henhold til ovenstående testplan. Overvej, om der er elementer i setuppet, som kan forstyrre målingerne.

Øvelse 3 – test af request til website

Vi skal i denne øvelse kigge på JMeters mulighed for at optage requests (recording). Lad os prøve at optage de kald, som JMeter foretager, når den kontakter forsiden på https://www.magenta.dk.

Proceduren er beskrevet i JMeters officielle dokumentation her: https://jmeter.apache.org/usermanual/jmeter_proxy_step_by_step.html.

Prøv at følge trinene i guiden og se, om du kan få det til at fungere.

Bemærk: erfaringen, i forhold til performance testing med open source værktøjet JMeter, har vist at der er problemer med at få JMeter proxy’en til at fungere i Chrome, så det anbefales at bruge Firefox i denne øvelse.

Performance testing med open source JMeter