背景
某客戶實施DAP,在上線前需要對DAP進行壓力測試,有專門的壓力測試環境,並且要求併發能夠達到1000,團隊使用jmeter作為壓測工具,整個系統架構很簡單瀏覽器->Nginx->Tomcat
,在壓測的時候碰到以下問題
- 對DAP流程提交介面進行壓測,壓測不透過
- 部署一個僅僅返回請求引數,沒有任何業務邏輯,壓測不透過
- 繞過Nginx,直接對Tomcat進行壓測,壓測透過
- 直接對Nginx進行壓測,壓測Nginx welcome頁面,壓測不透過
並且對Nginx進行了大量的調優,能調的引數基本都試過,壓測不透過,總結下來就是,只要經過Nginx,壓測就不透過,看來問題出現在Nginx上
環境資訊
- Nginx:16CPU 64G記憶體
- Nginx配置,這裡只列幾個比較重要的引數
worker_processes 16;
worker_connections 1000;
keepalive_timeout 60;
這些引數都調整過,對結果影響不大,當然如果調的太極端,比如worker_processes設定為1,肯定是會報錯的。
- Tomcat:16CPU 64G記憶體
這個配置Nginx跑1000併發完全是足夠的
排查
先看下兩個測試結果對比
- 壓測tomcat簡單介面,併發1000,迴圈50次,總共50000次請求
壓測結果
所有請求沒有出現Error
- 壓測Nginx welcome頁面,併發1000,迴圈50次,總共50000次請求
有百分之0.31%的錯誤率,雖然不高,但這個錯誤率是一直有的,而且如果說Nginx的壓測不如Tomcat,相信這個結果大家都接受不了,Nginx是負載均衡產品中公認最強的產品,一個是負載均衡,一個是應用伺服器,負載均衡最重要的就是併發能力,應用伺服器最重要的是業務能力,如果Tomcat在併發能力上超過Nginx,可能會顛覆很多人的認知。所以這其中肯定是有問題的。
Nginx壓測請求的錯誤主要集中在以下幾點
- java.net.ConnectionException: Connection refused: connect
- java.net.SocketException: Connection reset
- java.net.SocketException: Unexpected end of file from server
- org.apache.http.NoHttpResponseException: failed to respond
基本上是網路錯誤,為了排除網路錯誤,做了兩個測試
本地執行
我自己電腦(MAC)開nginx和tomcat,用jmeter進行壓測,結果更不理想,也是1000併發
雖然有這麼高的錯誤率,但是不管是nginx還是tomcat,並沒有報錯,這能說明什麼問題呢,說明很可能是核心層面就報錯了,也就是請求根本就沒進來
Linux主機執行
Jmeter支援在LInux下執行,也支援命令列模式,因此可以考慮在內網伺服器找一臺同網段主機作為壓測機器,步驟如下
- 將jmeter安裝包上傳到Linux壓測機並解壓
- 在本地配好測試計劃,儲存為jmx檔案,並將jmx檔案上傳至Linux壓測機
- 執行以下命令以命令列模式開啟壓測
apache-jmeter-5.4.1/bin/jmeter.sh -n -t plan.jmx -l plan.jtl
- 將結果檔案plan.jtl下載到本地,在彙總報告中點選Browser開啟檔案
錯誤率為0,結合本地執行的結果,可以猜測跟壓測機的環境有關。
壓測機
本次使用的壓測機是一臺windows 7主機,如果是壓測機的原因,那麼為什麼壓tomcat就沒問題,壓nginx就有問題,兩次壓測到底區別在哪,我們可以用wireshark進行抓包,看兩次壓測在網路包上有什麼不同
- Nginx壓測抓包,發現有大量RST的包,並且持續快速出現
RST是連線關閉時會傳送的資料包
- Tomcat壓測抓包也有RST的包,但是速度明顯較慢,而且數量不多
也就是說,Nginx壓測不斷在建立連線和關閉連線,tomact建立連線和關閉連線動作並沒有那麼頻繁,我們可以在windows上用以下命令檢視連線情況
netstat -a | find /i /c "TIME_WAIT"
該命令可以統計當前系統處於TIME_WAIT狀態的連線數,TIME_WAIT表示連線處於即將關閉的狀態,這時候連線所佔用的埠依然無法釋放,無法進行再次分配,如果短時間內產生大量的TIME_WAIT連線,容易導致埠號耗盡以至於無法建立新的連線,服務無法響應
- Tomcat壓測 TIME_WAIT連線數情況
TIME_WAIT
表示等待關閉的連線數,可以看到緩慢增長,並且達到兩千左右停止增長
- Nginx壓測TIME_WAIT連線數情況
可以看到快速增長,並且總數可以達到2w以上,最多可以達到4w,所以兩次壓測的區別就是TIME_WAIT的數量, 那為什麼會產生這種結果,以下是我的個人猜測
nginx採用的是epoll非阻塞模型,tomcat採用的是執行緒模型,一個請求一個執行緒,屬於阻塞模型,所以nginx可以段時間內"吃掉"大量的連線,tomcat需要排隊進入,這樣就造成了以上現象,nginx短時間建立大量連線,tomcat則是緩慢增加連線
結論
windows作為壓測機進行高併發壓測並不合適,因為會在短時間內產生大量連線,windows作為工作PC,在這方面處理能力不如Linux,加上網路波動等因素,容易造成錯誤,造成壓測結果失真,雖然可以透過最佳化部分引數降低錯誤率,但解決不了根本問題,建議透過同網段Linux主機作為壓測機,測試計劃可以在windows進行配置,結果分析也可以在windows中完成,但執行測試任務建議在Linux主機上進行。