1. 介紹web
隨着雲原生應用和微服務的流行也催生了對嵌入式Servlet容器需求的增加。爲更加簡單的構建應用和服務,Spring Boot爲開發者提供了三種成熟的容器:Tomcat,Undertow和Jetty。spring
在本文中,咱們會演示了一種方法:測量啓動和增長負載時獲取的指標來快速的比較不一樣容器實現的性能差別。apache
2. 依賴編程
首先咱們在pom.xml中指定了spring-boot-starter-web 這個依賴,這是咱們爲咱們每個容器實現進行測量前所必須的具有。tomcat
一般的,咱們會指定使用 spring-boot-starter-parent 做爲咱們的父依賴,而後接着加入咱們須要的starter:服務器
<parent>jvm
<groupId>org.springframework.boot</groupId>spring-boot
<artifactId>spring-boot-starter-parent</artifactId>微服務
<version>2.0.3.RELEASE</version>工具
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2.1 Tomcat
由於在咱們spring-boot-starter-web在咱們的依賴中,默認採用的是Tomcat容器,所以咱們不須要再作更多的配置。
2.2 Jetty
爲了使用Jetty,咱們首先須要從spring-boot-starter-web中去掉spring-boot-starter-tomcat 這個依賴。
而後,咱們只須要簡單引入spring-boot-starter-jetty的依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
2.3 Undertow
設置Undertow的方式和Jetty相似,不過去除依賴後,咱們會使用spring-boot-starter-undertow 做爲咱們的依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
2.4 Actuator
咱們使用Spring Boot的Actuator組件來對系統進行壓力測試和查詢應用指標。
你能夠經過閱讀這篇文章來更加詳細的瞭解Actuator。本文中,咱們只須要在pom中添加這個依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.5 Apache Beach
Apache Bench是一個開源的負載測試工具,但它一般會和Apache Web 服務器捆綁在一塊兒。
Windows用戶能夠點擊此處進行下載。若是你的Windows電腦上已經有了這個工具,你應該能夠在你的apache/bin 目錄下找到ab.exe 。
若是你是Linux的用戶,你能夠經過apt-get命令來安裝ab
$ apt-get install apache2-utils
3. 啓動指標
3.1 蒐集
爲了蒐集咱們的啓動指標,咱們會在Spring Boot的ApplicationReadyEvent 註冊咱們關注的指標。
咱們直接使用Actuator組件提供的MeterRegistry工具,經過編程的方式來直接獲取咱們所關注的指標:
public class StartupEventHandler {
// logger, constructor
private String[] METRICS = {
"jvm.memory.used",
"jvm.classes.loaded",
"jvm.threads.live"};
private String METRIC_MSG_FORMAT = "Startup Metric >> {}={}";
private MeterRegistry meterRegistry;
@EventListener
public void getAndLogStartupMetrics(
ApplicationReadyEvent event) {
Arrays.asList(METRICS)
.forEach(this::getAndLogActuatorMetric);
}
private void processMetric(String metric) {
Meter meter = meterRegistry.find(metric).meter();
Map<Statistic, Double> stats = getSamples(meter);
logger.info(METRIC_MSG_FORMAT, metric, stats.get(Statistic.VALUE).longValue());
}
// other methods
}
爲了不人爲的經過Actuator的REST端點進行性能指標的查詢,咱們啓動一個獨立的JMX進程來記錄應用啓動應用時咱們所關注的指標數據。
3.2 選擇
Actuator能夠爲咱們提供了大量的指標數據。在應用啓動後,咱們選擇了三個具備表明性的指標,他們能夠展示系統運行時的關鍵點的概況。
jvm.memory.used JVM在啓動後總共使用的內存量
jvm.classes.loaded JVM中總共加載的class文件的數量
jvm.threads.live JVM中存活的線程數量。在咱們的測試中,這個值能夠展示爲處於"休息"狀態的線程的數量。
4. 運行時指標
4.1 蒐集
除了提供啓動指標, 當咱們啓動Apache Bench後,使用Actuator組件提供的/metrics端點做爲目標url進行請求,以使咱們的應用處於負載階段。
爲了測試一個真實的處於負載的應用,咱們可能更須要使用咱們的應用系統所提供的端點進行測試。
一旦咱們的應用啓動完成,咱們使用如下命令來啓動並執行的ab:
ab -n 10000 -c 10 http://localhost:8080/actuator/metrics
4.2 選擇
Apache Bench可以快速的給予咱們一些有用的信息:包括鏈接時間,在某一段時間的請求的佔比等。
爲了咱們的目的,咱們一般更加關注每秒請求個數和每一個請求的處理時間的均值。
5. 結果
在啓動階段,咱們經過對Tomcat,Jetty和Undertow所佔用內存的比較,咱們發現Jetty佔用的內存最小,Undertow次之,Tomcat最多。
在咱們的測量中,我麼還能發現Tomcat,Jetty和Undertow的性能比較:咱們能夠清楚的看到Undertow很明顯是最快的,而Jetty則相對於慢一些。
MetricTomcatJettyUndertowjvm.memory.used (MB)168155164jvm.classes.loaded986997849787jvm.threads.live251719Requests per second154216271650Average time per request (ms)6.4836.1486.059
請注意,咱們的這些指標都是在裸項目(沒有添加任何業務代碼的項目)下進行的測量。若是是本身的項目,那麼測量指標大機率會有不一樣。
6. 基準測試討論
開發適當的基準測試以充分測試容器實現的性能多是至關複雜的。爲了提取其中最關鍵的信息,可以清晰認識到要針對每一個具體問題所編寫出正確的測試案例是很是重要的。
值得注意的是,示例中使用了Actutor的HTTP GET請求做爲負載,以此來收集的所須要指標的測量值。
可預見的是,不一樣的工做負載會致使對容器實現的進行不一樣指標的測量和蒐集。若是須要更加健壯和精確的測量,創建一個更接近生產用例的測試計劃是一個很是好的辦法。
此外,更復雜的基準測試解決方案(如JMeter或Gatling)可能會獲得更有價值的測試結論。
7. 選擇容器
選擇一個合適的容器實現應當要基於多方面的考量,而不能僅僅是基於一些硬性指標的概況就作出倉促的選擇。適用性,特性,可配置性和策略一般也起到至關大的考量。
8. 結論
在本文中,咱們看了Tomcat,Jetty和Undertow的嵌入式的Servlet容器的實現。咱們經過Actuator暴露的metrics端點來測試了每個Servlet容器在使用默認配置時的啓動後的運行時指標。
咱們經過使用Apache Bench來對應用進行壓力測試,同時收集各項性能指標。
最後,咱們談論了這個策略的優點,並說起了當比較各個實現的基準時應當要熟記於心的幾個建議。和往常同樣,你能夠從Github上獲取項目中的全部源碼。