Sammenligning af integrerede servletcontainere i Spring Boot

1. Introduktion

Den stigende popularitet af cloud-native applikationer og mikrotjenester genererer en øget efterspørgsel efter indlejrede servletcontainere. Spring Boot giver udviklere mulighed for nemt at opbygge applikationer eller tjenester ved hjælp af de 3 mest modne containere til rådighed: Tomcat, Undertow og Jetty.

I denne vejledning demonstrerer vi en måde til hurtigt at sammenligne containerimplementeringer ved hjælp af metrics opnået ved opstart og under en vis belastning.

2. Afhængigheder

Vores opsætning for hver tilgængelige containerimplementering kræver altid, at vi erklærer en afhængighed af spring-boot-starter-web i vores pom.xml.

Generelt ønsker vi at specificere vores forælder som spring-boot-starter-parent, og inkluder derefter de startere, vi ønsker:

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web 

2.1. Tomcat

Der kræves ingen yderligere afhængigheder, når du bruger Tomcat, fordi den er inkluderet som standard, når du bruger spring-boot-starter-web.

2.2. Anløbsbro

For at kunne bruge Jetty skal vi først udelukke spring-boot-starter-tomcat fra spring-boot-starter-web.

Derefter erklærer vi simpelthen en afhængighed af spring-boot-starter-anløbsbro:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-jetty 

2.3. Undertow

Opsætning til Undertow er identisk med Jetty, bortset fra at vi bruger spring-boot-starter-undertow som vores afhængighed:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-undertow 

2.4. Aktuator

Vi bruger Spring Boot's Actuator som en bekvem måde at både understrege systemet og spørge efter målinger.

Tjek denne artikel for detaljer om aktuator. Vi tilføjer simpelthen en afhængighed i vores pom for at gøre det tilgængeligt:

 org.springframework.boot spring-boot-starter-actuator 

2.5. Apache bænk

Apache Bench er et open source-belastningstestværktøj, der leveres sammen med Apache-webserveren.

Windows-brugere kan downloade Apache fra en af ​​de tredjepartsleverandører, der er linket her. Hvis Apache allerede er installeret på din Windows-maskine, skal du kunne finde ab.exe i din apache / bin vejviser.

Hvis du bruger en Linux-maskine, ab kan installeres ved hjælp af apt-get med:

$ apt-get installer apache2-utils

3. Startmetrics

3.1. Kollektion

For at indsamle vores opstartsmålinger registrerer vi en begivenhedshåndterer, der kan affyre Spring Boot's ApplicationReadyEvent.

Vi udtrækker programmatisk de metrics, vi er interesseret i, ved direkte at arbejde med MeterRegistry brugt af aktuatorkomponenten:

@Komponent offentlig klasse StartupEventHandler {// logger, konstruktør privat streng [] METRICS = {"jvm.memory.used", "jvm.classes.loaded", "jvm.threads.live"}; privat streng METRIC_MSG_FORMAT = "Startmetric >> {} = {}"; private MeterRegistry meterRegistry; @EventListener offentlig ugyldighed getAndLogStartupMetrics (ApplicationReadyEvent begivenhed) {Arrays.asList (METRICS) .forEach (dette :: getAndLogActuatorMetric); } privat ugyldighed processMetric (String metric) {Meter meter = meterRegistry.find (metric) .meter (); Kortstatistik = getSamples (meter); logger.info (METRIC_MSG_FORMAT, metric, stats.get (Statistic.VALUE) .longValue ()); } // andre metoder}

Vi undgår behovet for manuelt at spørge Actuator REST-slutpunkter eller at køre en uafhængig JMX-konsol ved at logge interessante målinger ved opstart i vores begivenhedshåndterer.

3.2. Udvælgelse

Der er et stort antal målinger, som aktuator leverer ud af kassen. Vi valgte 3 metrics, der hjælper med at få et overblik på højt niveau af nøglekarakteristikker, når serveren er oppe:

  • jvm.memory.used - den samlede hukommelse, der er brugt af JVM siden opstart
  • jvm.classes.loaded - det samlede antal indlæste klasser
  • jvm.threads.live - det samlede antal aktive tråde. I vores test kan denne værdi ses som trådtalet "i ro"

4. Kørselstidsmålinger

4.1. Kollektion

Ud over at levere startmetrics bruger vi / metrics slutpunkt eksponeret af aktuatoren som mål-URL, når vi kører Apache Bench for at sætte applikationen under belastning.

For at teste en ægte applikation under belastning kan vi i stedet bruge slutpunkter leveret af vores applikation.

Når serveren er startet, får vi en kommandoprompt og udfører ab:

ab -n 10000 -c 10 // localhost: 8080 / aktuator / metrics

I kommandoen ovenfor har vi specificeret i alt 10.000 anmodninger ved hjælp af 10 samtidige tråde.

4.2. Udvælgelse

Apache Bench er i stand til meget hurtigt at give os nogle nyttige oplysninger, herunder forbindelsestider og procentdelen af ​​anmodninger, der serveres inden for en bestemt tid.

Til vores formål vi fokuserede på anmodninger pr. sekund og tid pr. anmodning (gennemsnit).

5. Resultater

Ved opstart fandt vi det Tomcat, Jetty og Undertow's hukommelsesaftryk var sammenlignelig med Undertow, der kræver lidt mere hukommelse end de to andre, og Jetty kræver det mindste beløb.

For vores benchmark fandt vi det udførelsen af ​​Tomcat, Jetty og Undertow var sammenlignelig men det Undertow var helt klart den hurtigste og Jetty kun lidt mindre hurtig.

MetriskTomcatAnløbsbroUndertow
jvm.memory.used (MB)168155164
jvm.classes.loaded986997849787
jvm.threads.live251719
Anmodninger pr. Sekund154216271650
Gennemsnitlig tid pr. Anmodning (ms)6.4836.1486.059

Bemærk, at målingerne naturligvis er repræsentative for det bare-bone-projekt; metrics for din egen applikation vil helt sikkert være anderledes.

6. Benchmark-diskussion

Det kan blive kompliceret at udvikle passende benchmarktest for at udføre grundige sammenligninger af serverimplementeringer. For at udtrække de mest relevante oplysninger, det er afgørende at have en klar forståelse af, hvad der er vigtigt for den pågældende brugssag.

Det er vigtigt at bemærke, at de benchmarkmålinger, der er indsamlet i dette eksempel, blev udført ved hjælp af en meget specifik arbejdsbyrde bestående af HTTP GET-anmodninger til et aktuatorendepunkt.

Det forventes, at forskellige arbejdsbelastninger sandsynligvis vil resultere i forskellige relative målinger på tværs af containerimplementeringer. Hvis der kræves mere robuste eller præcise målinger, ville det være en meget god idé at oprette en testplan, der mere matchede produktionsanvendelsessagen.

Derudover vil en mere sofistikeret benchmarking-løsning som JMeter eller Gatling sandsynligvis give mere værdifuld indsigt.

7. Valg af en container

Valg af den rigtige containerimplementering skal sandsynligvis baseres på mange faktorer, der ikke kan sammenfattes pænt med en håndfuld målinger alene. Komfortniveau, funktioner, tilgængelige konfigurationsindstillinger og politik er ofte lige så vigtige, hvis ikke mere.

8. Konklusion

I denne artikel kiggede vi på Tomcat, Jetty og Undertow integrerede servletcontainerimplementeringer. Vi undersøgte køreegenskaberne for hver container ved opstart med standardkonfigurationerne ved at se på metrics eksponeret af aktuatorkomponenten.

Vi udførte en konstrueret arbejdsbyrde mod det kørende system og målte derefter ydeevnen ved hjælp af Apache Bench.

Til sidst diskuterede vi fordelene ved denne strategi og nævnte et par ting, man skal huske på, når man sammenligner implementeringsbenchmarks. Som altid kan al kildekode findes på GitHub.