Skip to content

Latest commit

 

History

History
626 lines (504 loc) · 36.5 KB

README.md

File metadata and controls

626 lines (504 loc) · 36.5 KB

Quarkus Event Bus Logging Filter JAX-RS

Keep a Changelog v1.1.0 badge License: MIT code of conduct

Build with Maven CI Docker build CI Docker build native amd64

Quality Gate Status

Docker Image Version (tag)

Questo progetto è un'applicazione Quarkus che mostra come realizzare un sistema che sia capace di tracciare le richieste JAX-RS in arrivo e in uscita dall'applicazione su diversi canali di storage, come ad esempio un database MongoDB, SQL o un broker AMQP sfruttando l'Event Bus di Quarkus.

Flusso Applicazione Quarkus

Figura 1 - Flusso dell'applicazione Quarkus

Se vuoi saperne di più su Quarkus, visita il sito ufficiale quarkus.io. A seguire trovi le istruzioni per eseguire l'applicazione in modalità sviluppo e creare un eseguibile nativo.

Requisiti

La tabella seguente elenca i requisiti necessari per l'implementazione ed esecuzione del progetto Quarkus.

Nome Opzionale Descrizione
Java JDK 17/21 NO Implementazione di OpenJDK 17/21. È possibile usare qualunque delle implementazioni disponibili. Per questo articolo è stata usata la versione 21 di OpenJDK e l'implementazione di Amazon Corretto 21.0.2.
Git NO Tool di versioning.
Maven 3.9.6 NO Tool di build per i progetti Java e di conseguenza Quarkus.
Quarkus 3.9.2 NO Framework Quarkus 3.9.2 la cui release note è disponibile qui https://quarkus.io/blog/quarkus-3-9-2-released/. Per maggiori informazioni per le release LTS fare riferimento all'articolo Long-Term Support (LTS) for Quarkus.
Quarkus CLI SI Tool a linea di comando che consente di creare progetti, gestire estensioni ed eseguire attività essenziali di creazione e sviluppo. Per ulteriori informazioni su come installare e utilizzare la CLI (Command Line Interface) di Quarkus, consulta la guida della CLI di Quarkus.
Docker v26 o Podman v4/5 NO Tool per la gestione delle immagini e l'esecuzione dell'applicazione in modalità container. La gestione delle immagini/container sarà necessaria nel momento in cui saranno sviluppati gli Event Handler che dovranno comunicare con i servizi esterni all'applicazione (vedi NoSQL, SQL, AMQP). La gestione delle immagini necessarie e container, sarà totalmente trasparente per noi sviluppatori in quanto a carico dei Dev Services di Quarkus.
GraalVM SI Per la build dell'applicazione in modalità nativa. Per maggiori informazioni fare riferimento alla documentazione Building a Native Executable.
Ambiente di sviluppo C SI Richiesto da GraalVM per la build dell'applicazione nativa. Per maggiori informazioni fare riferimento alla documentazione Building a Native Executable.
cURL 7.x/8.x SI Tool per il test dei Resource Endpoint (servizi REST)

Tabella 1 - Requisiti (anche opzionali) necessari per l'implementazione del progetto Quarkus

Le estensioni Quarkus utilizzate per l'implementazione del progetto sono le seguenti:

  • io.quarkus:quarkus-hibernate-validator ✔
  • io.quarkus:quarkus-mongodb-client ✔
  • io.quarkus:quarkus-openshift ✔
  • io.quarkus:quarkus-smallrye-health ✔
  • io.quarkus:quarkus-vertx ✔
  • io.quarkus:quarkus-messaging-amqp ✔
  • io.quarkus:quarkus-arc ✔
  • io.quarkus:quarkus-rest ✔
  • io.quarkus:quarkus-rest-jackson ✔
  • io.quarkus:quarkus-jdbc-h2 ✔
  • io.quarkus:quarkus-jdbc-postgresql ✔

È importante che abbiate installato e configurato correttamente il vostro ambiente di container runtime (Docker o Podman) al fine di eseguire l'applicazione in dev mode ed eseguire i test, entrambe le operazioni richiedono l'uso dei Dev Services di Quarkus (e di conseguenza del container runtime).

Dalla release 1.2.9 del progetto, la versione di Quarkus è stata aggiornata alla release 3.16.2.

Esecuzione dell'applicazione in Docker

Vorresti eseguire l'applicazione in un container e testare il funzionamento dell'applicazione fin da subito? All'interno del progetto è disponibile il file src/main/docker/docker-compose.yml che ti permette di eseguire l'applicazione in un container utilizzando Docker Compose o Podman Compose.

Ecco come fare utilizzando Podman Compose (non cambia nel caso di Docker Compose):

Dalla release 1.2.3 del progetto, il file docker-compose.yml è stato aggiornato aggiungendo il servizio di PostgreSQL.

A seguire il comando per avviare l'applicazione Quarkus in un container (compresi i servizi di supporto come MongoDB, AMQP, ecc.).

# Tramite Podman Compose (alternativa a Docker Compose)
podman-compose -f src/main/docker/docker-compose.yml up -d

Console 1 - Esegui l'applicazione Quarkus in un container (compresi i servizi di supporto come MongoDB, AMQP, ecc.)

Tramite il comando docker-compose o podman-compose verranno avviati i seguenti servizi:

  • MongoDB
  • AMQP (Apache ActiveMQ Artemis)
  • PostgreSQL (dalla release 1.2.3)
  • Applicazione Quarkus

L'immagine dell'applicazione Quarkus è disponibile su Docker Hub e questa è pubblicata grazie alla GitHub Actions .github/workflows/docker_publish.yml e .github/workflows/docker_publish_native_amd64.yml (per build e pubblicazione dell'immagine nativa x86-64).

Dopo aver eseguito il comando, puoi verificare che i servizi siano attivi tramite il comando docker ps o podman ps.

# Verifica i container attivi
podman ps

Console 2 - Verifica i container attivi

L'output del comando podman ps dovrebbe essere simile al seguente:

CONTAINER ID  IMAGE                                                    COMMAND               CREATED         STATUS                   PORTS                                                                                             NAMES
d021a5f570bc  docker.io/library/mongo:4.4                              mongod                40 seconds ago  Up 40 seconds            0.0.0.0:27017->27017/tcp                                                                          mongodb
4faee4a45565  quay.io/artemiscloud/activemq-artemis-broker:1.0.25      /opt/amq/bin/laun...  39 seconds ago  Up 39 seconds            0.0.0.0:5445->5445/tcp, 0.0.0.0:5672->5672/tcp, 0.0.0.0:8161->8161/tcp, 0.0.0.0:61616->61616/tcp  artemis
7a3d8e2e709e  docker.io/amusarra/eventbus-logging-filter-jaxrs:latest                        38 seconds ago  Up 38 seconds (healthy)  0.0.0.0:8080->8080/tcp, 0.0.0.0:8443->8443/tcp                                                    logging-filter

Console 3 - Output del comando podman ps

Il servizio logging-filter è l'applicazione Quarkus che è stata avviata in un container e che è pronta per essere utilizzata per testare i servizi REST esposti (fai attenzione che il servizio sia in stato healthy).

Sul docker-compose, per il servizio logging-filter, è stato abilitato il servizio di Health Check di Quarkus che verifica la salute dell'applicazione. Il servizio di Health Check è disponibile all'indirizzo http://localhost:8080/q/health.

  # The environment variables are used to configure the connection to the
  # Artemis message broker, MongoDB database e PostgreSQL database.
  # Se the application.properties file for more details about the names of the
  # environment variables.
  logging-filter:
    image: docker.io/amusarra/eventbus-logging-filter-jaxrs:latest
    container_name: logging-filter
    networks:
        - logging_filter_network
    environment:
        - AMQP_HOSTNAME=artemis
        - AMQP_PORT=5672
        - AMQP_USERNAME=artemis
        - AMQP_PASSWORD=artemis
        - MONGODB_CONNECTION_URL=mongodb://mongodb:27017/audit
        - DB_USERNAME=quarkus
        - DB_PASSWORD=quarkus
        - DB_URL=jdbc:postgresql://postgres:5432/quarkus_event_bus
        - JAVA_OPTS=-Xms100M -Xmx500M -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions
          -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=45 -XX:G1ReservePercent=10
          -XX:ConcGCThreads=4 -XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60
          -XX:ParallelGCThreads=4 -XX:+ExitOnOutOfMemoryError -Dcom.sun.management.jmxremote.port=9091
          -Dcom.sun.management.jmxremote.rmi.port=9091 -Dcom.sun.management.jmxremote.authenticate=false
          -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false
          -Djava.rmi.server.hostname=127.0.0.1
    ports:
      - "8080:8080"
      - "8443:8443"
      - "9091:9091"
    healthcheck:
      test: [ "CMD-SHELL", "curl --fail http://localhost:8080/q/health" ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    depends_on:
      - artemis
      - mongodb
      - postgres

Source 1 - Estratto del docker-compose.yml per il servizio logging-filter

Per testare il servizio REST esposto dall'applicazione Quarkus, puoi utilizzare il comando curl per inviare una richiesta HTTP al servizio REST.

# Invia una richiesta HTTP al servizio REST
curl -v --http2 \
  -H "Content-Type: application/json" \
  -d '{"message": "Test di tracking richiesta JAX-RS"}' \
  http://localhost:8080/api/rest/echo
  
# Risposta attesa
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> POST /api/rest/echo HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.4.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAAQAoAAAAAIAAAAA
> Content-Type: application/json
> Content-Length: 48
>
< HTTP/1.1 101 Switching Protocols
< connection: upgrade
< upgrade: h2c
* Received 101, Switching to HTTP/2
* Copied HTTP/2 data in stream buffer to connection buffer after upgrade: len=15
< HTTP/2 200
< content-type: application/json;charset=UTF-8
< content-length: 48
< set-cookie: user_tracking_id=f7cf38cd-a16d-4d53-91d3-5a3854f93e94;Version=1;Comment="Cookie di tracciamento dell'utente";Path=/;Max-Age=2592000;HttpOnly
< x-correlation-id: f5f0b80e-f550-45f4-9a75-41d33c6376f3
< x-pod-name: 7a3d8e2e709e
<
* Connection #0 to host localhost left intact
{"message": "Test di tracking richiesta JAX-RS"}%

Console 4 - Esempio di richiesta HTTP al servizio REST

Utilizzando il comando podman logs <container-id>, puoi verificare i log dell'applicazione Quarkus dove sono presenti le informazioni relative al tracciamento delle richieste JAX-RS. A seguire un esempio di output dei log dell'applicazione.

2024-04-23 11:57:43,965 DEBUG [it.don.eve.ws.fil.TraceJaxRsRequestResponseFilter] (executor-thread-35) La Request URI /api/rest/echo è tra quelle che devono essere filtrate
2024-04-23 11:57:43,966 DEBUG [it.don.eve.ws.fil.TraceJaxRsRequestResponseFilter] (executor-thread-35) Pubblicazione del messaggio della richiesta HTTP su Event Bus
2024-04-23 11:57:43,967 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Received event message from source virtual address: http-request and source component: it.dontesta.eventbus.consumers.http.HttpRequestConsumer for the target virtual addresses: sql-trace,nosql-trace,queue-trace
2024-04-23 11:57:43,968 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Sending event message to target virtual address: sql-trace
2024-04-23 11:57:43,968 ERROR [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Failed to receive response from target virtual address: sql-trace with failure: (NO_HANDLERS,-1) No handlers for address sql-trace
2024-04-23 11:57:43,968 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Sending event message to target virtual address: nosql-trace
2024-04-23 11:57:43,969 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Sending event message to target virtual address: queue-trace
2024-04-23 11:57:43,967 DEBUG [it.don.eve.ws.fil.TraceJaxRsRequestResponseFilter] (executor-thread-35) La Request URI /api/rest/echo è tra quelle che devono essere filtrate
2024-04-23 11:57:43,970 DEBUG [it.don.eve.ws.fil.TraceJaxRsRequestResponseFilter] (executor-thread-35) Pubblicazione del messaggio della risposta HTTP su Event Bus
2024-04-23 11:57:43,973 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Received event message from source virtual address: http-response and source component: it.dontesta.eventbus.consumers.http.HttpResponseConsumer for the target virtual addresses: sql-trace,nosql-trace,queue-trace
2024-04-23 11:57:43,976 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Sending event message to target virtual address: sql-trace
2024-04-23 11:57:43,977 ERROR [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Failed to receive response from target virtual address: sql-trace with failure: (NO_HANDLERS,-1) No handlers for address sql-trace
2024-04-23 11:57:43,977 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Sending event message to target virtual address: nosql-trace
2024-04-23 11:57:43,977 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Sending event message to target virtual address: queue-trace
2024-04-23 11:57:43,982 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Received response from target virtual address: nosql-trace with result: Documents inserted successfully with Id BsonObjectId{value=6627a2378d1ed50d0c256e95}
2024-04-23 11:57:43,982 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Received response from target virtual address: nosql-trace with result: Documents inserted successfully with Id BsonObjectId{value=6627a2378d1ed50d0c256e96}
2024-04-23 11:57:43,984 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Received response from target virtual address: queue-trace with result: Message sent to AMQP queue successfully!
2024-04-23 11:57:43,984 DEBUG [it.don.eve.con.eve.han.Dispatcher] (vert.x-eventloop-thread-0) Received response from target virtual address: queue-trace with result: Message sent to AMQP queue successfully!

Log 1 - Esempio di log dell'applicazione Quarkus

A questo punto puoi eseguire lo shutdown dell'applicazione Quarkus e dei servizi di supporto utilizzando il comando podman-compose -f src/main/docker/docker-compose.yml down o il relativo docker-compose.

Su asciinema.org è disponibile un video che mostra come eseguire l'applicazione Quarkus in un container utilizzando Podman.

asciicast

Potresti anche essere curioso a fare un semplice benchmark dell'applicazione Quarkus in un container. Per fare ciò, puoi utilizzare il comando h2load che è un benchmarking tool per HTTP/2 e HTTP/1.1. Ecco un esempio di come fare.

# Esegui il benchmark dell'applicazione Quarkus utilizzando il protocollo HTTP/2
# -n 100 indica il numero di richieste da inviare
# -c 5 indica il numero di connessioni da mantenere aperte
# -H "Content-Type: application/json" indica l'header Content-Type
# -H 'Accept-Encoding: gzip, deflate, br, zstd' indica l'header Accept-Encoding
# -d src/test/resources/payload-1.json indica il payload da inviare
h2load -n 100 -c 5 \
        -H "Content-Type: application/json" \
        -H 'Accept-Encoding: gzip, deflate, br, zstd' \
        -d src/test/resources/payload-1.json \
        https://0.0.0.0:8443/api/rest/echo

Console 5 - Esempio di benchmark dell'applicazione Quarkus

A seguire un esempio di output del comando h2load.

starting benchmark...
spawning thread #0: 5 total client(s). 100 total requests
TLS Protocol: TLSv1.3
Cipher: TLS_AES_256_GCM_SHA384
Server Temp Key: X25519 253 bits
Application protocol: h2
progress: 10% done
progress: 20% done
progress: 30% done
progress: 40% done
progress: 50% done
progress: 60% done
progress: 70% done
progress: 80% done
progress: 90% done
progress: 100% done

finished in 210.56ms, 474.93 req/s, 145.54KB/s
requests: 100 total, 100 started, 100 done, 100 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 100 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 30.64KB (31380) total, 18.71KB (19160) headers (space savings 32.54%), 9.57KB (9800) data
                     min         max         mean         sd        +/- sd
time for request:      970us    107.30ms      4.16ms     12.84ms    97.00%
time for connect:    62.28ms    165.11ms    103.21ms     42.95ms    80.00%
time to 1st byte:   115.42ms    169.90ms    148.03ms     29.64ms    60.00%
req/s           :      95.02      131.20      109.66       19.40    60.00%

Log 2 - Esempio di output del comando h2load

Qualche nota sulla configurazione di Podman

Nel caso in cui abbiate Podman al posto di Docker, potreste incontrare il problema mostrato seguire quanto avvierete l'applicazione.

...
2024-05-15 12:22:07,164 ERROR [org.tes.doc.DockerClientProviderStrategy] (build-43) Could not find a valid Docker environment. Please check configuration. Attempted configurations were:
	UnixSocketClientProviderStrategy: failed with exception InvalidConfigurationException (Could not find unix domain socket). Root cause AccessDeniedException (/var/run/docker.sock)
	DockerDesktopClientProviderStrategy: failed with exception NullPointerException (Cannot invoke "java.nio.file.Path.toString()" because the return value of "org.testcontainers.dockerclient.DockerDesktopClientProviderStrategy.getSocketPath()" is null)As no valid configuration was found, execution cannot continue.
...

Log 3 - Esempio di errore di configurazione di Podman

In questo caso, dovreste attivare il servizio podman.socket per le API service e in modo che il socket sia accessibile a tutti gli utenti. Per fare ciò, eseguire i seguenti comandi.

# I comandi seguenti devono essere eseguiti come utente normale (!= root)
# Abilita il servizio podman.socket per le API service in modalità user
systemctl --user start podman.socket

# Verifica che il socket sia stato creato
ls -l $XDG_RUNTIME_DIR/podman/podman.sock

# Verifica che il servizio podman.socket sia attivo
systemctl --user status podman.socket

# Export della variabile d'ambiente DOCKER_HOST
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock

Console 6 - Abilita il servizio podman.socket per le API service

Esecuzione dell'applicazione in dev mode

Puoi eseguire l'applicazione in modalità sviluppo che abilita il live coding utilizzando:

./mvnw compile quarkus:dev

Console 7 - Esecuzione dell'applicazione in modalità sviluppo

NOTE: Quarkus ora include una UI di sviluppo, disponibile solo in modalità sviluppo all'indirizzo http://localhost:8080/q/dev/.

Quarkus Dev UI

Figura 2 - Quarkus Dev UI

Packaging e avvio dell'applicazione

L'applicazione può essere preparata utilizzando:

./mvnw package

Console 8 - Packaging dell'applicazione

Il processo produrrà il file quarkus-run.jar in target/quarkus-app/. Questo non è un über-jar in quanto le dipendenze sono copiate nella directory target/quarkus-app/lib/.

L'applicazione è ora eseguibile utilizzando java -jar target/quarkus-app/quarkus-run.jar.

Se vuoi creare un über-jar, esegui il seguente comando:

./mvnw package -Dquarkus.package.type=uber-jar

Console 9 - Impacchettamento dell'applicazione come über-jar

L'applicazione, impacchettata come un über-jar, è ora eseguibile utilizzando java -jar target/*-runner.jar.

Creazione di un eseguibile nativo

Puoi creare un eseguibile nativo utilizzando:

./mvnw package -Dnative

Console 9 - Creazione di un eseguibile nativo

Nel caso in cui tu non avessi GraalVM installato, puoi eseguire la build dell'eseguibile nativo in un container utilizzando:

./mvnw package -Dnative -Dquarkus.native.container-build=true

Console 11 - Creazione di un eseguibile nativo in un container

Puoi eseguire l'eseguibile nativo con: ./target/eventbus-logging-filter-jaxrs-1.0.0-SNAPSHOT-runner

Se vuoi saperne di più sulla creazione di eseguibili nativi, consulta https://quarkus.io/guides/maven-tooling.

Scenari di Load Testing con JMeter e Taurus

All'interno del progetto è disponibile il file jmx src/test/jmeter/scenario_1.jmx che consente di eseguire un semplice di Load Testing con JMeter.

Lo scopo di questo semplice scenario è quello di testare il servizio REST api/rest/echo esposto dall'applicazione Quarkus e di verificare il comportamento del sistema sotto stress in termini di performance e scalabilità ma in particolare per mostrare la differenza tra le richieste HTTP/1.1 e HTTP/2 over TLS con e senza compressione GZIP.

Il Test Plan creato, prevede una serie di Thread Group che includono un sampler HTTP configurato opportunamente per il servizio REST api/rest/echo. I Thread Group sono:

  1. test in HTTPS/1.1
  2. test in HTTPS/2 over TLS
  3. test in HTTP/2 over TLS con compressione GZIP

La figura seguente mostra la configurazione del Test Plan con JMeter.

Configurazione Test Plan di JMeter

Figura 3 - Configurazione del Test Plan di JMeter

Ognuno dei tre test è quindi un Thread Group di JMeter che può essere configurato attraverso le User Defined Variables (vedi Figura 3) del Test Plan e in particolare:

  1. numberOfThreads: questo parametro indica il numero totale di thread (utenti virtuali) che saranno avviati durante l'esecuzione del test. Ogni thread simula un utente che interagisce con il sistema sotto test;
  2. rampUpPeriod: il periodo di ramp-up (in secondi) specifica quanto tempo JMeter deve impiegare per far partire tutti i thread specificati nel "Number of Threads". Ad esempio, se hai 100 thread e imposti un periodo di ramp-up di 10 secondi, JMeter inizierà un nuovo thread ogni 0.1 secondo (10 secondi/100 thread);
  3. loopCount: questo parametro definisce quante volte ogni thread eseguirà il set di campioni (richieste HTTP o altre operazioni) all'interno del Thread Group. Se imposti il Loop Count su 0, i thread continueranno a eseguire i campioni all'infinito finché il test non viene interrotto manualmente.

La figura seguente mostra come questi valori sono stati impostati sul Thread Group di JMeter.

Configurazione Thread Group JMeter

Figura 4 - Configurazione del Thread Group di JMeter

Per eseguire questo scenario di Load Testing è possibile utilizzare Taurus, un framework open source che automatizza i test di carico e le operazioni di test di performance. Taurus supporta JMeter, Gatling, Locust, Selenium e altri strumenti di test di carico.

Per l'installazione di Taurus, puoi seguire la guida ufficiale.

Il file di configurazione di Taurus src/test/jmeter/taurus/config.yml è stato creato per eseguire il Test Plan di JMeter. Ecco un esempio di come eseguire il Test Plan di JMeter con Taurus.

# Esegui il Test Plan di JMeter con Taurus
bzt -o modules.jmeter.properties.numberOfThreads=100 \
  -o modules.jmeter.properties.rampUpPeriod=0.5 \
  -o modules.jmeter.properties.loopCount=300 \
  -o modules.jmeter.properties.httpProtocol=https \
  -o modules.jmeter.properties.httpPort=8443 \
  -o modules.jmeter.properties.ipOrFQDN=localhost \
  src/test/jmeter/taurus/config.yml \
  src/test/jmeter/scenario_1.jmx

Console 12 - Esecuzione del Test Plan di JMeter con Taurus

Il comando bzt esegue il Test Plan di JMeter con Taurus e i parametri -o sono utilizzati per sovrascrivere i valori delle variabili definite nel file di configurazione di Taurus src/test/jmeter/taurus/config.yml che in questo caso agiscono sulle User Defined Variables del Test Plan di JMeter. Dal valore di ipOrFQDN si può notare che il test sarà eseguito in locale, per cui abbiate cura di avere l'applicazione Quarkus in esecuzione.

I Thread Group in questo caso sono stati configurati per simulare 100 utenti virtuali che inviano 300 richieste al servizio REST api/rest/echo esposto dall'applicazione Quarkus con un periodo di ramp-up di 0.5 secondi.

NOTA: I dati mostrati a seguire fanno riferimento all'esecuzione del Test Plan sull'ambiente Developer Sandbox di Red Hat OpenShift, con attivi tre pod dell'applicazione Quarkus, un pod per il servizio MongoDB e un pod per il servizio AMQP (Apache ActiveMQ Artemis).

Le due figure a seguire mostrano Taurus in esecuzione, rispettivamente all'inizio (dov'è mostrato lo stato di avanzamento) e alla fine del test (dov'è mostrato il report).

Taurus in esecuzione

Figura 5 - Taurus in esecuzione

Dal report di Taurus è possibile vedere i risultati del test di carico eseguito con JMeter. Dalla durata del test, al numero di richieste HTTP inviate, al tempo di risposta medio, etc. Da questo report è già possibile vedere come il tempo di risposta sia influenzato dal protocollo utilizzato (HTTP/1.1, HTTP/2) e dalla compressione GZIP.

Taurus Report

Figura 6 - Taurus Report

L'esecuzione del Test Plan di JMeter con Taurus produce all'interno della directory target/taurus/%Y-%m-%d_%H-%M-%S.%f i file di log più il jtl dei kpi da poter analizzare con JMeter.

Per esempio, la figura seguente, attraverso jp@gc - Transactions per Second, mostra il throughput del sistema durante il test di carico (dai dati letti dal file jtl kpi.jtl locato in target/taurus/%Y-%m-%d_%H-%M-%S.%f).

Throughput del sistema

Figura 7 - Throughput del sistema

Anche da questo grafico è possibile vedere come il throughput del sistema sia influenzato dal protocollo utilizzato e il protocollo HTTP/2 over TLS con compressione GZIP sia quello che offre le migliori performance.

Dalla release 1.2.2 del progetto, è disponibile lo scenario di Load Testing per testare i servizi JAX-RS collegati alle due entità ORM (Object Relational Mapping) che sono state implementate nel progetto e introdotte dalla release 1.2.0.

Per eseguire lo scenario di Load Testing, è possibile utilizzare il file jmx src/test/jmeter/scenario_2.jmx, di cui potete vedere la struttura aprendolo con JMeter. A seguire è mostrata la struttura del Test Plan di JMeter.

Configurazione Test Plan di JMeter Scenario 2

Figura 8 - Configurazione del Test Plan di JMeter (scenario 2 src/test/jmeter/scenario_2.jmx)

I thread group sono stati configurati con lo stesso principio del primo scenario di Load Testing, di conseguenza sono stati creati per versione di protocollo HTTP (HTTPS/1.1, HTTP/2 over TLS e compressed); per ognuno di essi è stato creato un flusso di richieste verso i servizi JAX-RS dell'entità ORM Owner e Horse (introdotte dalla versione 1.2.0 del progetto).

Per questo scenario, attraverso l'elemento di configurazione HTTP Header Manager, sono stati configurati un set di header HTTP custom e che riguardano nello specifico delle informazioni su JMeter; questi sono:

  1. X-TestCaseId: un identificativo univoco del test case
  2. X-TestPlanName: il nome del test plan
  3. X-TestThreadGroupName: il nome del thread group
  4. X-TestThreadNumber: il numero del thread

Queste informazioni possono essere utili per tracciare le richieste HTTP inviate da JMeter e per identificare il test. A seguire un esempio di una richiesta eseguita da JMeter e tracciata su MongoDB dove sono evidenti gli header HTTP custom.

{
  "_id" : ObjectId("66425a820d65f7240e2ba113"),
  "X-Correlation-ID" : "bc187f1f-9c6c-499b-9d13-0b87b31d2abb",
  "remote-ip-address" : "127.0.0.1",
  "headers" : {
    "Accept" : [
      "*/*"
    ],
    "X-TestThreadGroupName" : [
      "HTTPS/1.1"
    ],
    "Connection" : [
      "keep-alive"
    ],
    "User-Agent" : [
      "Java/21.0.2"
    ],
    "X-TestPlanName" : [
      "modified_scenario_2.jmx"
    ],
    "Host" : [
      "127.0.0.1:8443"
    ],
    "X-TestCaseId" : [
      "005044d0-9848-4f22-8e50-02fa395a5ede"
    ],
    "Content-Length" : [
      "296"
    ],
    "Content-Type" : [
      "application/json;charset=UTF-8"
    ],
    "X-TestThreadNumber" : [
      "1"
    ]
  },
  "body" : "{\r\n  \"name\": \"Crimson Comet-updated\",\r\n  \"sex\": \"F\",\r\n  \"coat\": \"chestnut\",\r\n  \"breed\": \"Appaloosa\",\r\n  \"dateOfBirth\": \"2004-01-19\",\r\n  \"registrationNumber\": \"0FOTDW12MI531U\",\r\n  \"microchipNumber\": \"C782CF2I1IN\",\r\n  \"passportNumber\": \"39K4CK1I3ZDU4\",\r\n  \"height\": 134,\r\n  \"owners\": [{\"id\": 3}]\r\n}",
  "uri-info" : "https://127.0.0.1:8443/api/rest/repository/horse/v1/6",
  "local-date-time-in" : "2024-05-13T20:22:58.622629",
  "method" : "PUT",
  "media-type" : "application/json",
  "acceptable-language" : "[]",
  "acceptable-media-types" : "[*/*]"
}

Log 4 - Esempio di richiesta HTTP tracciata su MongoDB

È possibile eseguire questo scenario sempre con Taurus utilizzando comando bzt come mostrato in precedenza. A seguire è riportato il comando per eseguire lo scenario di Load Testing con Taurus.

# Esegui lo scenario di Load Testing con Taurus
bzt -o modules.jmeter.properties.numberOfThreads=1 \
  -o modules.jmeter.properties.rampUpPeriod=5 \
  -o modules.jmeter.properties.loopCount=25 \
  -o modules.jmeter.properties.httpProtocol=https \
  -o modules.jmeter.properties.httpPort=8443 \
  -o modules.jmeter.properties.ipOrFQDN=127.0.0.1 \
  src/test/jmeter/taurus/config.yml \
  src/test/jmeter/scenario_2.jmx

Console 13 - Esecuzione dello scenario di Load Testing con Taurus

Accesso alla Java Management Extensions (JMX)

Dalla versione 1.2.4 del progetto è possibile accedere alla Java Management Extensions (JMX) dell'applicazione Quarkus in esecuzione quando questa è avviata utilizzando il docker-compose. Questo è possibile grazie alla configurazione mostrata a seguire e in particolare i parametri JAVA_OPTS che abilitano la JMX.

  logging-filter:
    # Use the following image if you want to use the pre-built image from Docker Hub:
    # docker.io/amusarra/eventbus-logging-filter-jaxrs:latest
    image: docker.io/amusarra/eventbus-logging-filter-jaxrs:latest
    container_name: logging-filter
    networks:
      - logging_filter_network
    environment:
      - JAVA_OPTS=-Xms100M -Xmx500M -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions
        -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=45 -XX:G1ReservePercent=10
        -XX:ConcGCThreads=4 -XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60
        -XX:ParallelGCThreads=4 -XX:+ExitOnOutOfMemoryError -Dcom.sun.management.jmxremote.port=9091
        -Dcom.sun.management.jmxremote.rmi.port=9091 -Dcom.sun.management.jmxremote.authenticate=false
        -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false
        -Djava.rmi.server.hostname=127.0.0.1

Source 2 - Estratto del docker-compose.yml per il servizio logging-filter con JMX abilitato

Una volta che il container è in esecuzione, è possibile accedere alla JMX dell'applicazione Quarkus utilizzando un client JMX come JConsole, VisualVM o Java Mission Control. In questo caso, la stringa di connessione JMX è service:jmx:rmi:///jndi/rmi://localhost:9091/jmxrmi. A seguire un esempio di connessione tramite VisualVM.

Connessione JMX con VisualVM

Figura 9 - Connessione JMX con VisualVM

La figura a seguire mostra invece il monitoraggio dell'applicazione, dove sono presenti le informazioni relative alla memoria, al garbage collector, al class loader, al thread, ecc.

Monitoraggio JMX con VisualVM

Figura 10 - Monitoraggio JMX con VisualVM

In ambiente OpenShift, è possibile accedere alla JMX dell'applicazione Quarkus utilizzando per esempio il progetto Cryostat (JFR for Containerized Java Applications).

Guida ai servizi e alle estensioni utilizzate

  • MongoDB client (guide): Connect to MongoDB in either imperative or reactive style
  • Eclipse Vert.x (guide): Write reactive applications with the Vert.x API
  • OpenShift (guide): Generate OpenShift resources from annotations
  • ArC (guide): Build time CDI dependency injection
  • Messaging - AMQP Connector (guide): Connect to AMQP with Reactive Messaging
  • REST (guide): A Jakarta REST implementation utilizing build time processing and Vert.x. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it.
  • REST Jackson (guide): Jackson serialization support for Quarkus REST. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it
  • Hibernate Validator (guide): Validate object properties (field, getter) and method parameters for your beans (REST, CDI, Jakarta Persistence)
  • Using Podman with Quarkus (guide)
  • Simplified Hibernate ORM with Panache (guide): Simplify your persistence layer with Panache
  • Configura data sources in Quarkus (guide):
    • Connect to a H2 database using JDBC
    • Connect to a PostgreSQL database using JDBC

Team Tools

alt tag

Antonio Musarra's Blog Team would like inform that JetBrains is helping by provided IDE to develop the application. Thanks to its support program for an Open Source projects!

alt tag

This project is using SonarCloud for code quality. Thanks to SonarQube Team for free analysis solution for open source projects.