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.
Metriek | Kater | Steiger | Undertow |
---|---|---|---|
jvm.memory.used (MB) | 168 | 155 | 164 |
jvm.classes.loaded | 9869 | 9784 | 9787 |
jvm.threads.live | 25 | 17 | 19 |
Verzoeken per seconde | 1542 | 1627 | 1650 |
Gemiddelde tijd per verzoek (ms) | 6.483 | 6.148 | 6.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.