Embedded Servlet Containers in Spring Boot vergelijken

1. Inleiding

De stijgende populariteit van cloud-native applicaties en microservices genereert een toenemende vraag naar embedded servlet-containers. Met Spring Boot kunnen ontwikkelaars eenvoudig applicaties of services bouwen met behulp van de 3 meest volwassen containers die beschikbaar zijn: Tomcat, Undertow en Jetty.

In deze zelfstudie demonstreren we een manier om containerimplementaties snel te vergelijken met behulp van metrische gegevens die zijn verkregen bij het opstarten en onder enige belasting.

2. Afhankelijkheden

Onze configuratie voor elke beschikbare containerimplementatie vereist altijd dat we een afhankelijkheid van spring-boot-starter-web in onze pom.xml.

Over het algemeen willen we onze ouder specificeren als spring-boot-starter-parent, en voeg vervolgens de starters toe die we willen:

 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. Kater

Er zijn geen verdere afhankelijkheden vereist bij het gebruik van Tomcat, omdat het standaard wordt meegeleverd bij het gebruik van spring-boot-starter-web.

2.2. Steiger

Om Jetty te kunnen gebruiken, moeten we eerst uitsluiten spring-boot-starter-tomcat van spring-boot-starter-web.

Vervolgens verklaren we eenvoudig een afhankelijkheid van spring-boot-starter-steiger:

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

2.3. Undertow

Instellen voor Undertow is identiek aan Jetty, behalve dat we spring-boot-starter-onderstroom als onze afhankelijkheid:

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

2.4. Actuator

We zullen de Actuator van Spring Boot gebruiken als een gemakkelijke manier om zowel het systeem te benadrukken als om metrische gegevens te vragen.

Bekijk dit artikel voor details over Actuator. We voegen eenvoudig een afhankelijkheid toe aan onze pom om het beschikbaar te maken:

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

2.5. Apache-bank

Apache Bench is een open source hulpprogramma voor het testen van belasting dat gebundeld wordt met de Apache-webserver.

Windows-gebruikers kunnen Apache downloaden van een van de externe leveranciers die hier worden gelinkt. Als Apache al op uw Windows-computer is geïnstalleerd, zou u ab.exe in uw apache / bin directory.

Als je een Linux-machine gebruikt, ab kan worden geïnstalleerd met apt-get met:

$ apt-get install apache2-utils

3. Opstartstatistieken

3.1. Verzameling

Om onze opstartstatistieken te verzamelen, registreren we een gebeurtenishandler om te vuren op Spring Boot's ApplicationReadyEvent.

We extraheren programmatisch de statistieken waarin we geïnteresseerd zijn door rechtstreeks samen te werken met het MeterRegistry gebruikt door de actuatorcomponent:

@Component openbare klasse StartupEventHandler {// logger, constructor privé String [] METRICS = {"jvm.memory.used", "jvm.classes.loaded", "jvm.threads.live"}; private String METRIC_MSG_FORMAT = "Opstartstatistiek >> {} = {}"; privé MeterRegistry meterRegistry; @EventListener openbare ongeldige getAndLogStartupMetrics (ApplicationReadyEvent-gebeurtenis) {Arrays.asList (METRICS) .forEach (this :: getAndLogActuatorMetric); } private void processMetric (String metrisch) {Meter meter = meterRegistry.find (metrisch) .meter (); Kaartstatistieken = getSamples (meter); logger.info (METRIC_MSG_FORMAT, metrisch, stats.get (Statistic.VALUE) .longValue ()); } // andere methodes }

We vermijden de noodzaak om Actuator REST-eindpunten handmatig te doorzoeken of om een ​​zelfstandige JMX-console uit te voeren door interessante statistieken bij het opstarten te loggen in onze gebeurtenishandler.

3.2. Selectie

Er is een groot aantal statistieken die Actuator uit de doos levert. We hebben drie statistieken geselecteerd die helpen om een ​​algemeen overzicht te krijgen van de belangrijkste runtime-kenmerken zodra de server is opgestart:

  • jvm.memory.used - het totale geheugen dat door de JVM is gebruikt sinds het opstarten
  • jvm.classes.loaded - het totale aantal geladen klassen
  • jvm.threads.live - het totale aantal actieve threads. In onze test kan deze waarde worden gezien als het aantal threads 'in rust'

4. Runtime-statistieken

4.1. Verzameling

Naast het verstrekken van opstartstatistieken, gebruiken we de / metrics endpoint weergegeven door de Actuator als de doel-URL wanneer we Apache Bench draaien om de applicatie te belasten.

Om een ​​echte applicatie onder belasting te testen, kunnen we in plaats daarvan endpoints gebruiken die door onze applicatie worden geleverd.

Zodra de server is gestart, krijgen we een opdrachtprompt en voeren we uit ab:

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

In de bovenstaande opdracht hebben we in totaal 10.000 verzoeken gespecificeerd met 10 gelijktijdige threads.

4.2. Selectie

Apache Bench kan ons zeer snel wat nuttige informatie geven, waaronder verbindingstijden en het percentage verzoeken dat binnen een bepaalde tijd wordt behandeld.

Voor onze doeleinden, we concentreerden ons op verzoeken per seconde en tijd per verzoek (gemiddeld).

5. Resultaten

Bij het opstarten vonden we dat de geheugenvoetafdruk van Tomcat, Jetty en Undertow was vergelijkbaar waarbij Undertow iets meer geheugen nodig heeft dan de andere twee en Jetty het kleinste bedrag nodig heeft.

Voor onze benchmark hebben we dat gevonden de prestaties van Tomcat, Jetty en Undertow waren vergelijkbaar maar dat Undertow was duidelijk de snelste en Jetty maar iets minder snel.

MetriekKaterSteigerUndertow
jvm.memory.used (MB)168155164
jvm.classes.loaded986997849787
jvm.threads.live251719
Verzoeken per seconde154216271650
Gemiddelde tijd per verzoek (ms)6.4836.1486.059

Merk op dat de statistieken natuurlijk representatief zijn voor het kale project; de statistieken van uw eigen applicatie zullen zeker anders zijn.

6. Benchmarkbespreking

Het ontwikkelen van geschikte benchmarktests om grondige vergelijkingen van serverimplementaties uit te voeren, kan ingewikkeld worden. Om de meest relevante informatie te extraheren, het is van cruciaal belang om een ​​duidelijk begrip te hebben van wat belangrijk is voor de betreffende use case.

Het is belangrijk op te merken dat de benchmarkmetingen die in dit voorbeeld zijn verzameld, zijn uitgevoerd met behulp van een zeer specifieke werkbelasting die bestaat uit HTTP GET-verzoeken aan een Actuator-eindpunt.

Er wordt verwacht dat verschillende workloads waarschijnlijk zullen resulteren in verschillende relatieve metingen tussen containerimplementaties. Als er robuustere of nauwkeurigere metingen nodig waren, zou het een heel goed idee zijn om een ​​testplan op te stellen dat beter aansluit bij de gebruiksscenario van de productie.

Bovendien zou een meer geavanceerde benchmarking-oplossing zoals JMeter of Gatling waarschijnlijk meer waardevolle inzichten opleveren.

7. Een container kiezen

Het selecteren van de juiste containerimplementatie zou waarschijnlijk gebaseerd moeten zijn op veel factoren die niet netjes kunnen worden samengevat met een handvol statistieken alleen. Comfortniveau, functies, beschikbare configuratie-opties en beleid zijn vaak even belangrijk, zo niet meer.

8. Conclusie

In dit artikel hebben we gekeken naar de implementaties van de Tomcat, Jetty en Undertow embedded servlet-containers. We hebben de runtime-kenmerken van elke container bij het opstarten onderzocht met de standaardconfiguraties door te kijken naar metrische gegevens die worden weergegeven door de Actuator-component.

We hebben een gekunstelde workload uitgevoerd op het actieve systeem en vervolgens de prestaties gemeten met Apache Bench.

Ten slotte hebben we de voordelen van deze strategie besproken en een paar dingen genoemd waarmee u rekening moet houden bij het vergelijken van implementatiebenchmarks. Zoals altijd is alle broncode te vinden op GitHub.