Servlet 3 性能調(diào)優(yōu)

Servlet 3 早在 2011 年推出,但很多 web 項目還是使用 Servlet 2.5。這些 web 項目業(yè)務(wù)相對較重、單機(jī)負(fù)載相對較低,Servlet 2.5 由于更少切換線程比 Servlet 3 更加穩(wěn)定。

隨著微服務(wù)的發(fā)展,web 層不斷演進(jìn),涌現(xiàn)出越來越多的 API 網(wǎng)關(guān)。API 網(wǎng)關(guān)將 web 層的業(yè)務(wù)剝離開,專注于安全防護(hù)和路由轉(zhuǎn)發(fā)。這種重 IO 輕 CPU 的場景非常適合使用 Servlet 3。

通常異步 Servlet 項目中有 3 類線程池:Tomcat IO 工作線程池、業(yè)務(wù)線程池、RPC 線程池。

下面介紹 Servlet 優(yōu)化的五個階段,這五個階段大致分為三類優(yōu)化手段:線程隔離、無鎖處理和更換容器。

第一階段:純同步

第一階段采用同步 Servlet,Tomcat 線程進(jìn)入業(yè)務(wù)代碼并執(zhí)行預(yù)處理、RPC 調(diào)用、結(jié)果處理
壓測到 1000 QPS 時 AVG(20)、99 線(70)、999 線(75),整體平穩(wěn)

第二階段:偽異步

異步 Servlet 中通過 servletRequest.startAsync 開啟異步,asyncContext.dispatch 重新分發(fā)請求、asyncContext.complete 結(jié)束異步。Spring MVC 的異步是先開啟異步、執(zhí)行業(yè)務(wù)、重新分發(fā)請求。這種方式是為了兼容 Spring MVC 的同步實現(xiàn),但是由于兩次分發(fā)導(dǎo)致代碼更復(fù)雜、并可能對 Servlet 帶來更大的壓力。

在第二階段的時候采用類似的實現(xiàn):

  1. Tomcat 線程進(jìn)入業(yè)務(wù)代碼并預(yù)處理請求
  2. Tomcat 線程開啟異步并異步請求 RPC 服務(wù)
  3. RPC 回調(diào)后重新分發(fā)請求
  4. Tomcat 線程進(jìn)入業(yè)務(wù)代碼并處理請求結(jié)果

壓測到 1000 QPS 時 AVG(18)、99 線(56)、999 線(60),整體平穩(wěn),異步占優(yōu)
壓測到 1400 QPS 時 AVG(23)、99 線(80)、999 線(85),整體平穩(wěn),異步占優(yōu)
壓測到 2000 QPS 時 AVG(32)、99 線(300)、999 線(320),波動較大

第三階段:全異步

項目在第三階段的時候采用全異步:

  1. Tomcat 線程進(jìn)入業(yè)務(wù)代碼并開啟異步
  2. Tomcat 線程提交業(yè)務(wù)線程并返回
  3. 業(yè)務(wù)線程預(yù)處理并調(diào)用 RPC 服務(wù)
  4. RPC 回調(diào)后提交業(yè)務(wù)線程
  5. 業(yè)務(wù)線程處理請求結(jié)果并結(jié)束異步

壓測到 2500 QPS 時 AVG(44)、99 線(83)、999 線(85),整體平穩(wěn),時有抖動
壓測到 3000 QPS 時 AVG(70)、99 線(180)、999 線(190),整體平穩(wěn),時有抖動

第四階段:異步優(yōu)化

業(yè)界 4 核 8 g 異步 Servlet 的機(jī)器吞吐量能夠達(dá)到 1w+ QPS

1.觀察機(jī)器在壓測時的性能指標(biāo),QPS 3000 時出現(xiàn) full gc

2.壓測結(jié)束后 Dump 機(jī)器內(nèi)存后發(fā)現(xiàn)無大對象,但是有大量 byte [] 和 char [] 對象

3.使用 JProfiler 分析 byte [] 的來源,可能來自 Tomcat 的 IO

在對比 Tomcat 線程數(shù)后猜測,可能是 Tomcat 線程池打滿所致。同時在 Tomcat 日志中也出現(xiàn)大量隊列已滿的報錯

4.嘗試調(diào)整 Tomcat 線程池配置:增加線程數(shù)量、采用 Http11Nio2Protocol 處理協(xié)議。調(diào)整后壓測吞吐量沒有提升。https://renwole.com/archives/357

<Executor
 name="tomcatThreadPool"
 namePrefix="catalina-exec-"
 maxThreads="500"
 minSpareThreads="30"
 maxIdleTime="60000"
 prestartminSpareThreads = "true"
 maxQueueSize = "100"
/>
<Connector
 executor="tomcatThreadPool"
 port="8080"
 protocol="org.apache.coyote.http11.Http11Nio2Protocol"
 connectionTimeout="60000"
 maxConnections="10000"
 redirectPort="8443"
 enableLookups="false"
 acceptCount="100"
 maxPostSize="10485760"
 maxHttpHeaderSize="8192"
 compression="on"
 disableUploadTimeout="true"
 compressionMinSize="2048"
 acceptorThreadCount="2"
 URIEncoding="utf-8"
 processorCache="20000"
 tcpNoDelay="true"
 connectionLinger="5"
 server="Server Version 11.0"
 />

5.修改業(yè)務(wù)線程池大小
壓測到 5000 QPS 時 AVG(59)、99 線(130)、999 線(145),整體平穩(wěn)

6.修改調(diào)用下游服務(wù)的方式,基于回調(diào) => 同步

7.對比業(yè)務(wù)各階段耗時,增加服務(wù)調(diào)用線程池線程
壓測到 6000 QPS 時高點 AVG(348)、99 線(500)、999 線(1000),整體平穩(wěn)

8.異步 Servlet 開啟異步后超時自動結(jié)束請求,RPC 在回調(diào)時如果已經(jīng)超時會報狀態(tài)異常,因此對 onTimeout 和 onComplete 加上同步鎖

9.移除 RPC 調(diào)用,mock 服務(wù)返回結(jié)果
壓測到 10000 QPS 時高點 AVG(12)、99 線(504)、999 線(1000),CPU 幾乎打滿

10.調(diào)整業(yè)務(wù)線程組,預(yù)處理和調(diào)用服務(wù)使用同一線程、RPC 回調(diào)和處理返回結(jié)果使用同一線程,弱化 CPU 輪轉(zhuǎn)。壓測到高點時開始出現(xiàn)線程阻塞
壓測到 6000 QPS 時高點 AVG(8)、99 線(35)、999 線(1000),CPU 幾乎打滿

11.縮短 RPC 服務(wù)超時時間 200 -> 50
壓測到 4000 時開始出現(xiàn)線程阻塞

12.移除 AsyncContext 監(jiān)聽中 onTimeout 和 onComplete 上的同步鎖

13.使用 servlet 3.1 nio,注冊 reader listener 和 write listener 異步讀寫

壓測到 7000 QPS 時高點 AVG(10)、99 線(30)、999 線(1000)

第四階段總結(jié):

  1. 異步 IO 能一定程度上提高并發(fā),在傳輸量不大的情況下提高并不明顯
  2. 高并發(fā)同步調(diào)用會阻塞 IO 線程
  3. Tomcat 內(nèi)部沒有復(fù)用 bytebuffer 導(dǎo)致請求量大時新生代 gc 頻繁,最后引起服務(wù)超時,日志阻塞等一系列問題

第五階段:Jetty 容器

Jetty 底層對 ByteBuffer 對象的復(fù)用和線程池的處理有更好的優(yōu)化。
在第五階段,更換 Servlet 容器為 Jetty 進(jìn)行調(diào)優(yōu)。
壓測到 11000 QPS 時高點 AVG(40)、99 線(90)、999 線(140),整體平穩(wěn)

第五階段總結(jié):

  1. 在高并發(fā)的場景中,Jetty 的性能比 Tomcat 要強(qiáng),耗時曲線非常平穩(wěn)
  2. 使用 Jetty 容器后,10000 QPS 時 AVG(5)、99 線(20)、999 線(20
最后編輯于
?著作權(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)容