Spring Boot中嵌入式Servlet容器的比較

1. 介紹

隨著云原生應(yīng)用和微服務(wù)的流行也催生了對嵌入式Servlet容器需求的增長。為更加簡單的構(gòu)建應(yīng)用和服務(wù),Spring Boot為開發(fā)者提供了三種成熟的容器:Tomcat,Undertow和Jetty。

在本文中,我們會演示了一種方法:測量啟動和增加負載時獲取的指標(biāo)來快速的比較不同容器實現(xiàn)的性能差異。

2. 依賴

首先我們在pom.xml中指定了spring-boot-starter-web 這個依賴,這是我們?yōu)槲覀兠恳粋€容器實現(xiàn)進行測量前所必須的具備。

通常的,我們會指定使用 spring-boot-starter-parent 作為我們的父依賴,然后接著加入我們需要的starter:

<parent>

<groupId>org.springframework.boot</groupId>

<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

設(shè)置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組件來對系統(tǒng)進行壓力測試和查詢應(yīng)用指標(biāo)。

你可以通過閱讀這篇文章來更加詳細的了解Actuator。本文中,我們只需要在pom中添加這個依賴:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

2.5 Apache Beach

Apache Bench是一個開源的負載測試工具,但它通常會和Apache Web 服務(wù)器捆綁在一起。

Windows用戶可以點擊此處進行下載。如果你的Windows電腦上已經(jīng)有了這個工具,你應(yīng)該可以在你的apache/bin 目錄下找到ab.exe 。

如果你是Linux的用戶,你可以通過apt-get命令來安裝ab

$ apt-get install apache2-utils

3. 啟動指標(biāo)

3.1 搜集

為了搜集我們的啟動指標(biāo),我們會在Spring Boot的ApplicationReadyEvent 注冊我們關(guān)注的指標(biāo)。

我們直接使用Actuator組件提供的MeterRegistry工具,通過編程的方式來直接獲取我們所關(guān)注的指標(biāo):

@Component

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端點進行性能指標(biāo)的查詢,我們啟動一個獨立的JMX進程來記錄應(yīng)用啟動應(yīng)用時我們所關(guān)注的指標(biāo)數(shù)據(jù)。

3.2 選擇

Actuator可以為我們提供了大量的指標(biāo)數(shù)據(jù)。在應(yīng)用啟動后,我們選擇了三個具有代表性的指標(biāo),他們可以展現(xiàn)系統(tǒng)運行時的關(guān)鍵點的概況。

jvm.memory.used JVM在啟動后總共使用的內(nèi)存量

jvm.classes.loaded JVM中總共加載的class文件的數(shù)量

jvm.threads.live JVM中存活的線程數(shù)量。在我們的測試中,這個值可以展現(xiàn)為處于"休息"狀態(tài)的線程的數(shù)量。

4. 運行時指標(biāo)

4.1 搜集

除了提供啟動指標(biāo), 當(dāng)我們啟動Apache Bench后,使用Actuator組件提供的/metrics端點作為目標(biāo)url進行請求,以使我們的應(yīng)用處于負載階段。

為了測試一個真實的處于負載的應(yīng)用,我們可能更需要使用我們的應(yīng)用系統(tǒng)所提供的端點進行測試。

一旦我們的應(yīng)用啟動完成,我們使用以下命令來啟動并執(zhí)行的ab:

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

4.2 選擇

Apache Bench能夠快速的給予我們一些有用的信息:包括連接時間,在某一段時間的請求的占比等。

為了我們的目的,我們通常更加關(guān)注每秒請求個數(shù)和每個請求的處理時間的均值。

5. 結(jié)果

在啟動階段,我們通過對Tomcat,Jetty和Undertow所占用內(nèi)存的比較,我們發(fā)現(xiàn)Jetty占用的內(nèi)存最小,Undertow次之,Tomcat最多。

在我們的測量中,我么還能發(fā)現(xiàn)Tomcat,Jetty和Undertow的性能比較:我們可以清楚的看到Undertow很明顯是最快的,而Jetty則相對于慢一些。

MetricTomcatJettyUndertowjvm.memory.used (MB)168155164jvm.classes.loaded986997849787jvm.threads.live251719Requests per second154216271650Average time per request (ms)6.4836.1486.059

請注意,我們的這些指標(biāo)都是在裸項目(沒有添加任何業(yè)務(wù)代碼的項目)下進行的測量。如果是自己的項目,那么測量指標(biāo)大概率會有不同。

6. 基準(zhǔn)測試討論

開發(fā)適當(dāng)?shù)幕鶞?zhǔn)測試以充分測試容器實現(xiàn)的性能可能是相當(dāng)復(fù)雜的。為了提取其中最關(guān)鍵的信息,能夠清晰認識到要針對每個具體問題所編寫出正確的測試案例是非常重要的。

值得注意的是,示例中使用了Actutor的HTTP GET請求作為負載,以此來收集的所需要指標(biāo)的測量值。

可預(yù)見的是,不同的工作負載會導(dǎo)致對容器實現(xiàn)的進行不同指標(biāo)的測量和搜集。如果需要更加健壯和精確的測量,建立一個更接近生產(chǎn)用例的測試計劃是一個非常好的辦法。

此外,更復(fù)雜的基準(zhǔn)測試解決方案(如JMeter或Gatling)可能會得到更有價值的測試結(jié)論。

7. 選擇容器

選擇一個合適的容器實現(xiàn)應(yīng)當(dāng)要基于多方面的考量,而不能僅僅是基于一些硬性指標(biāo)的概況就做出倉促的選擇。適用性,特性,可配置性和策略通常也起到相當(dāng)大的考量。

8. 結(jié)論

在本文中,我們看了Tomcat,Jetty和Undertow的嵌入式的Servlet容器的實現(xiàn)。我們通過Actuator暴露的metrics端點來測試了每一個Servlet容器在使用默認配置時的啟動后的運行時指標(biāo)。

我們通過使用Apache Bench來對應(yīng)用進行壓力測試,同時收集各項性能指標(biāo)。

最后,我們談?wù)摿诉@個策略的優(yōu)勢,并提及了當(dāng)比較各個實現(xiàn)的基準(zhǔn)時應(yīng)當(dāng)要熟記于心的幾個建議。和往常一樣,你可以從Github上獲取項目中的所有源碼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容