1. 程式人生 > 實用技巧 >19丨Tomcat:中介軟體監控及常用計數器解析

19丨Tomcat:中介軟體監控及常用計數器解析

在當今Spring Cloud微服務架構盛行的時代,Tomcat仍然作為應用最廣的應用伺服器而存在著,所以我們不得不說一說對它的效能分析。

很多時候,我們做效能測試分析時,都會把Tomcat這類的應用弄混淆。對它的監控和分析,總是會和JDK、框架程式碼、業務程式碼混合來看,這就導致了分析上的混亂。我們應該把這些分析內容分隔開來,哪些是tomcat,哪些是JDK等。

在我看來,Tomcat、WebLogic、WebSphere、JBoss等,它們都具有同樣的分析思路。因為Tomcat的市場範圍更大,所以,今天,我們以它為例來說明這類應用應該如何分析。

首先我們得知道它的架構是什麼樣的。

這是一個在網上隨處可見的架構圖,它能告訴我們Tomcat內部如何運作。如果你有興趣,還可以看一下官方對它的架構描述。

然而,我們做效能分析的人真的要完全掌握這些細節嗎?當然不是。從經驗上來說,基本上有幾大方面,是Tomcat優化時需要關注的。

如下圖所示:

最上面,我放了兩個框,分別是作業系統和JDK。因為要調優Tomcat,和這兩者非常相關,但是作業系統和JDK又各自有獨立的分析邏輯,而在本篇中,我專門講Tomcat型別的元件,所以上面兩塊的內容我將盡量不涉及,以免混亂。

在Tomcat的效能分析中,我將我認為重要的幾個技術點列在了思維導圖中,同時也對它們做了重要程度的標識。在我分析經驗中,這些內容已經包括了大部分的優化場景。

執行模式之爭

有很多人對執行模式非常敏感,大家也看到經常有文章說:“對於效能來說,顯然是BIO<NIO<APR的。”然而也有人做過測試說,其實不見得BIO效能就最差,這取決於應用場景;也有人說在壓力低的情況下,顯然BIO的效能更高。

從我的經驗上來說,真的沒必要糾結這一點。本著對Tomcat官方的信任,我覺得最好就是用官方給的預設執行模式,它肯定是經過了更嚴格的測試才被選擇的。這就跟相信世上好人多是一樣的道理。

現在新的Tomcat版本中預設的是NIO了,你可以在啟動日誌中看到相應的資訊,如下所示:

21-Jan-2020 16:50:57.989 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["https-jsse-nio-443"]

簡單地說BIO和NIO的區別如下面兩張圖所示。

BIO圖示:

NIO圖示:


要理解這個區別,首先得知道幾個知識點:

  1. Acceptor是TCP層面的東西,它負責完成TCP握手的過程,放入全連線佇列,然後將資料生成request,呼叫servlet容器處理。
  2. 而Worker乾的就是接到request資料,處理後給出response。
  3. Poller是一個佇列,屬於典型的生產者-消費者模式。

知道了這些,你就會明白其實對於Acceptor和Worker本身來說,仍然是阻塞的。而這個Poller只能是在大併發的時候,可以hold住更多的請求而已,看起來Tomcat處理請求的容量增加了,但是我們還是要在具體的應用中去測試,來比對響應時間的差異。

但是還有一點區別我們得知道,Tomcat的keepAliveTimeout引數預設使用的是connectionTimeout的值。這樣一來,由於使用BIO時,Acceptor讀取socket中的資料並傳遞給Worker這個過程是阻塞的,意味著當代碼執行到Worker中時,這個socket仍然被佔著;而使用NIO時,Acceptor讀取socket資料後交給了Poller了,Worker從Poller中得到請求內容並處理,這個過程就分開了,這樣Worker在處理時就不會阻塞socket,所以Tomcat可以處理更多的socket,這才是NIO效能提升的關鍵點。

而APR是個啥呢?它是利用了OS中的能力來進行高併發地檔案讀取或者網路傳輸,來提高對靜態檔案的處理。有很多網上的實驗結果都可以證明,在具體的應用中它並沒有比NIO的效能高到哪裡去,並且配置起來還麻煩,所以這個模式現在並沒有很廣泛的使用。

所以在Tomcat中,執行模式之爭應該說已經不存在了。

請求量、請求時間、響應時間

這是我希望你能在分析Tomcat時關注的內容。我們有很多種方式可以看這些資訊,最簡單的就是訪問日誌了。通過在conf/server.xml中做如下配置:

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
             prefix="localhost_access_log" suffix=".txt"
             pattern="%h %l %u %t &quot;%r&quot; %s %b %D %F" />

其中%D就是請求時間,%F是響應時間。配置了之後,在日誌中就會看到如下內容:

172.17.211.144 - - [21/Jan/2020:18:06:57 +0800] "POST /back/save HTTP/1.1" 200 14 29 29
172.17.211.144 - - [21/Jan/2020:18:06:57 +0800] "GET /validate/code/pic HTTP/1.1" 200 541 5 0

最後兩列就是請求時間和響應時間。通過這兩個時間的比對,你就可以知道,Tomcat本身消耗了多少時間以及Tomcat之後的操作又消耗了多少時間。

當然,如果你喜歡的話,也可以看這樣的監控圖表。

這是一個小工具Probe的監控資料,從這裡,你可以知道Tomcat這段時間處理了多少請求,以及處理這些請求的時間、最大時間、最小時間和平均時間。

但是!我不建議用這個工具來監控Tomcat,因為它效能差。你可能會問,那你還說它幹嗎?因為其他的效能監控工具中,很少有見到這個角度的圖表展示,在這裡只是為了告訴你,分析Tomcat全域性效能狀態時,可以通過總請求數,以及平均響應時間來看Tomcat的全域性處理能力如何。

當然這些資料你同樣可以通過分析訪問日誌獲取。

顯然有了這些資料,我們就可以做一個大體的判斷了。在服務節點多的時候,只要看這裡的平均響應時間,你就能知道在這個Tomcat上有沒有消耗掉你在壓力工具中看到的響應時間。

下面我通過測試結果來說明幾個Tomcat中常用的優化動作。

在展示優化動作之前,先看一下connector基本配置:

<Connector
    SSLEnabled="true"
    acceptCount="100"
    clientAuth="false"
    disableUploadTimeout="true"
    enableLookups="false"
    maxThreads="25"
    port="443"
    connectionTimeout="20000"
    keystoreFile="/PathToTomcat/bin/server.keystore"
    keystorePass="12345678"
    protocol="org.apache.coyote.http11.Http11NioProtocol"
    scheme="https"
    secure="true"
    sslProtocol="TLS" />

這只是一個基本配置。至於是不是最優的配置,我們需要在針對一個應用測試的過程中慢慢來看。

比如有人會說,你這裡為什麼不配置minSpareThreads和maxSpareThreads之類的引數?首先,我們要知道,為什麼要配置這兩個引數?對於一個執行緒數超高的應用來說,長期維護大量的執行緒肯定會導致作業系統中context switch的增加,在一個應用的波峰波谷差別較大的時候,我們用這兩個引數其實是為了減少在波谷時產生的維護成本。但是同時你也要知道,線上程不夠用的時候,開新的執行緒也同樣需要成本,所以這兩個值需不需要配置,完全取決於應用場景的具體測試結果。

總之,所有的配置都需要在具體的應用場景測試了之後,再下定論,別憑感覺。

協議 HTTP、HTTPS

我們知道在HTTPS的協議中,因為加入了SSL證書會導致效能下降,但是對有些應用來說,又不得不用SSL證書。在這裡我自己配置了一個證書,來給你看看證書對效能產生的影響。

我的證書配置是這樣的:

  • 根證書:RSA證書、sha256,8192位
  • 中級證書:RSA,sha256、4096位
  • 終端證書:RSA,sha256、4096位

一般情況下,SSL證書都是分為三層的。在這個例子中,我生成的時候還特意用了高位數,位數越高,對效能影響越大,因為計算成本增加了。現在我們在市場上買的證書,根據價值的不同,加密方式和位數都會不一樣,請稍微注意一下。

下面來看看測試結果。

Tomcat with SSL:

summary +    588 in 00:00:13 =   46.0/s Avg:    10 Min:     1 Max:   804 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   4403 in 00:00:30 =  146.8/s Avg:     4 Min:     0 Max:    87 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary =   4991 in 00:00:43 =  116.7/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)
summary +   7107 in 00:00:30 =  237.1/s Avg:     4 Min:     0 Max:    77 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =  12098 in 00:01:13 =  166.3/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  11121 in 00:00:30 =  370.7/s Avg:     4 Min:     0 Max:    72 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =  23219 in 00:01:43 =  226.0/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  12709 in 00:00:30 =  423.6/s Avg:     4 Min:     0 Max:    87 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  35928 in 00:02:13 =  270.6/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  14548 in 00:00:30 =  485.0/s Avg:     4 Min:     0 Max:    69 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =  50476 in 00:02:43 =  310.1/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  15810 in 00:00:30 =  527.0/s Avg:     5 Min:     0 Max:    83 Err:     0 (0.00%) Active: 7 Started: 7 Finished: 0
summary =  66286 in 00:03:13 =  343.9/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  15242 in 00:00:30 =  508.0/s Avg:     5 Min:     0 Max:    77 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  81528 in 00:03:43 =  366.0/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  16709 in 00:00:30 =  557.1/s Avg:     5 Min:     0 Max:    75 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary =  98237 in 00:04:13 =  388.7/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  17099 in 00:00:30 =  570.0/s Avg:     6 Min:     0 Max:   161 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 115336 in 00:04:43 =  407.9/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)

Tomcat without SSL:

summary +     12 in 00:00:03 =    4.2/s Avg:   148 Min:     4 Max:   937 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   3531 in 00:00:30 =  117.8/s Avg:     4 Min:     0 Max:    63 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary =   3543 in 00:00:33 =  107.8/s Avg:     4 Min:     0 Max:   937 Err:     0 (0.00%)
summary +   7283 in 00:00:30 =  242.8/s Avg:     4 Min:     0 Max:    90 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =  10826 in 00:01:03 =  172.2/s Avg:     4 Min:     0 Max:   937 Err:     0 (0.00%)
summary +   9554 in 00:00:30 =  318.5/s Avg:     3 Min:     0 Max:    35 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =  20380 in 00:01:33 =  219.5/s Avg:     4 Min:     0 Max:   937 Err:     0 (0.00%)
summary +  14747 in 00:00:30 =  491.6/s Avg:     3 Min:     0 Max:    49 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  35127 in 00:02:03 =  285.9/s Avg:     3 Min:     0 Max:   937 Err:     0 (0.00%)
summary +  16844 in 00:00:30 =  561.4/s Avg:     3 Min:     0 Max:    47 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =  51971 in 00:02:33 =  340.0/s Avg:     3 Min:     0 Max:   937 Err:     0 (0.00%)
summary +  17547 in 00:00:30 =  585.0/s Avg:     3 Min:     0 Max:    47 Err:     0 (0.00%) Active: 7 Started: 7 Finished: 0
summary =  69518 in 00:03:03 =  380.2/s Avg:     3 Min:     0 Max:   937 Err:     0 (0.00%)
summary +  18798 in 00:00:30 =  626.6/s Avg:     4 Min:     0 Max:   213 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  88316 in 00:03:33 =  414.9/s Avg:     3 Min:     0 Max:   937 Err:     0 (0.00%)
summary +  18529 in 00:00:30 =  617.6/s Avg:     4 Min:     0 Max:   204 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary = 106845 in 00:04:03 =  439.9/s Avg:     3 Min:     0 Max:   937 Err:     0 (0.00%)
summary +  18837 in 00:00:30 =  627.9/s Avg:     4 Min:     0 Max:    53 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 125682 in 00:04:33 =  460.6/s Avg:     4 Min:     0 Max:   937 Err:     0 (0.00%)

這裡稍微囉嗦一下,我們以這種終端直接輸出的資料看JMeter的結果時,主要關注下"summary +"的資料,因為"summary ="的資料是整個場景執行的平均資料。另外,第一行的資料會不準確,可以忽略,如果你把粒度調低一些,可以看到更細的資料。

通過上面的資料可以看到,沒有SSL比有SSL證書是要高出一些TPS的。如下圖所示:

顯然SSL證書對效能有明顯的影響了,最大的影響到18.93%,是在8個執行緒時,而在五六個執行緒時,TPS損耗有13%左右。

這和加密位數、應用場景等都有關係,所以這一段可以給你的結論就是:SSL證書對效能會有損耗。但具體損耗是多少,在你的應用場景中需要具體測試。

執行緒池

Tomcat的執行緒池,一直是調優Tomcat的重點物件。在我的工作經驗中,我發現經常有人不太清楚對Tomcat應該配置多大的執行緒池。

之前,我見過有一個人在一個4C8G的機器上把一個Tomcat節點的執行緒池配置到了4000。我問他為什麼要這麼配置,他說想支援4000的併發使用者。

我們先不說他有沒有理解線上使用者、併發使用者和TPS之間的邏輯關係,只說把Tomcat配置為4000這個事情。就算Tomcat能支撐得住4000,但機器能撐得住嗎?結果還沒跑多少壓力執行緒,作業系統的CS就不斷走高,消耗了大量的sy CPU,只有少量的us CPU能處理正常的業務。

然後我告訴他把Tomcat執行緒數調到預設的200先看看,結果TPS上升了好幾倍。

這就是對執行緒在系統中執行的邏輯不理解導致的情況。

我們在測試的時候,先得學會判斷:執行緒數到底夠不夠用。要是不夠用,但又有足夠的硬體資源,那你可以增加執行緒。

但是在增加執行緒之前,先要判斷,程式碼是不是執行得足夠快,如果程式碼本身就慢,那就先優化程式碼,再調整執行緒。

這裡就有一個小的分析鏈路了。如下所示:

怎麼來判斷程式碼執行得足夠快呢?

下面我們來看幾個例子,然後我會說一下如何判斷程式碼快不快(當然這個具體的應用也有關,你還需要在具體的應用中做詳細地分析哦)。

場景一:當壓力執行緒遠遠小於服務端執行緒數時

測試結果:

summary +    930 in 00:00:16 =   59.7/s Avg:     7 Min:     0 Max:   922 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   4546 in 00:00:30 =  151.6/s Avg:     3 Min:     0 Max:    46 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary =   5476 in 00:00:46 =  120.2/s Avg:     3 Min:     0 Max:   922 Err:     0 (0.00%)
summary +   5822 in 00:00:30 =  194.0/s Avg:     2 Min:     0 Max:    32 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary =  11298 in 00:01:16 =  149.5/s Avg:     3 Min:     0 Max:   922 Err:     0 (0.00%)
summary +   5295 in 00:00:24 =  216.5/s Avg:     2 Min:     0 Max:    26 Err:     0 (0.00%) Active: 0 Started: 1 Finished: 1
summary =  16593 in 00:01:40 =  165.9/s Avg:     2 Min:     0 Max:   922 Err:     0 (0.00%)

執行緒監控結果:

jvisuavlvm的thread監控圖是每秒重新整理一次,其中橙色代表TIMED_WAITING狀態,沒活幹;綠色代表RUNNABLE狀態,在幹活。

通過這個測試結果,你可以看到,在只有一個壓力執行緒的情況下,這10個Worker是輪流提供響應的。

這就是典型的執行緒足夠用的狀態

場景二:當壓力執行緒數通過遞增,慢慢超過服務端執行緒數時


測試結果:

summary +   4529 in 00:00:22 =  203.6/s Avg:     2 Min:     0 Max:   464 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary +  11023 in 00:00:30 =  367.7/s Avg:     2 Min:     0 Max:    71 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =  15552 in 00:00:52 =  297.8/s Avg:     2 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  15131 in 00:00:30 =  504.4/s Avg:     2 Min:     0 Max:   166 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  30683 in 00:01:22 =  373.2/s Avg:     2 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  17420 in 00:00:30 =  580.7/s Avg:     3 Min:     0 Max:    68 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =  48103 in 00:01:52 =  428.6/s Avg:     3 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  17416 in 00:00:30 =  580.5/s Avg:     3 Min:     0 Max:    72 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  65519 in 00:02:22 =  460.7/s Avg:     3 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  17389 in 00:00:30 =  579.6/s Avg:     4 Min:     0 Max:    71 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary =  82908 in 00:02:52 =  481.4/s Avg:     3 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18591 in 00:00:30 =  619.8/s Avg:     4 Min:     0 Max:    82 Err:     0 (0.00%) Active: 11 Started: 11 Finished: 0
summary = 101499 in 00:03:22 =  501.9/s Avg:     3 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18692 in 00:00:30 =  623.1/s Avg:     5 Min:     0 Max:    72 Err:     0 (0.00%) Active: 12 Started: 12 Finished: 0
summary = 120191 in 00:03:52 =  517.6/s Avg:     4 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18577 in 00:00:30 =  619.2/s Avg:     6 Min:     0 Max:    83 Err:     0 (0.00%) Active: 14 Started: 14 Finished: 0
summary = 138768 in 00:04:22 =  529.2/s Avg:     4 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  19371 in 00:00:30 =  645.7/s Avg:     6 Min:     0 Max:   113 Err:     0 (0.00%) Active: 15 Started: 15 Finished: 0
summary = 158139 in 00:04:52 =  541.2/s Avg:     4 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18891 in 00:00:30 =  629.7/s Avg:     7 Min:     0 Max:   146 Err:     0 (0.00%) Active: 17 Started: 17 Finished: 0
summary = 177030 in 00:05:22 =  549.4/s Avg:     4 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  19075 in 00:00:30 =  635.6/s Avg:     7 Min:     0 Max:    99 Err:     0 (0.00%) Active: 18 Started: 18 Finished: 0
summary = 196105 in 00:05:52 =  556.7/s Avg:     5 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18782 in 00:00:30 =  625.4/s Avg:     8 Min:     0 Max:   122 Err:     0 (0.00%) Active: 20 Started: 20 Finished: 0
summary = 214887 in 00:06:22 =  562.1/s Avg:     5 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18911 in 00:00:30 =  631.3/s Avg:     8 Min:     0 Max:   146 Err:     0 (0.00%) Active: 21 Started: 21 Finished: 0
summary = 233798 in 00:06:52 =  567.2/s Avg:     5 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18153 in 00:00:30 =  605.1/s Avg:     9 Min:     0 Max:   147 Err:     0 (0.00%) Active: 23 Started: 23 Finished: 0
summary = 251951 in 00:07:22 =  569.7/s Avg:     5 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  14704 in 00:00:30 =  490.1/s Avg:    10 Min:     0 Max:   175 Err:     0 (0.00%) Active: 24 Started: 24 Finished: 0
summary = 266655 in 00:07:52 =  564.7/s Avg:     6 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  18196 in 00:00:30 =  606.6/s Avg:    10 Min:     0 Max:   147 Err:     0 (0.00%) Active: 26 Started: 26 Finished: 0
summary = 284851 in 00:08:22 =  567.2/s Avg:     6 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  17768 in 00:00:30 =  592.3/s Avg:    10 Min:     0 Max:   227 Err:     0 (0.00%) Active: 27 Started: 27 Finished: 0
summary = 302619 in 00:08:52 =  568.6/s Avg:     6 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  16754 in 00:00:30 =  558.2/s Avg:    12 Min:     0 Max:   218 Err:     0 (0.00%) Active: 29 Started: 29 Finished: 0
summary = 319373 in 00:09:22 =  568.0/s Avg:     7 Min:     0 Max:   464 Err:     0 (0.00%)
summary +  17216 in 00:00:30 =  574.0/s Avg:    12 Min:     0 Max:   249 Err:     0 (0.00%) Active: 30 Started: 30 Finished: 0
summary = 336589 in 00:09:52 =  568.3/s Avg:     7 Min:     0 Max:   464 Err:     0 (0.00%)

執行緒監控結果:

在這個場景中,我特意把壓力工具中的執行緒數設定得高於Tomcat執行緒數,並且通過遞增的方式加壓。

一開始執行緒數是足夠用的,還有挺多的時間處於空閒狀態。但隨著壓力的增加,Tomcat的執行緒越來越忙,直到不夠用,於是Tomcat就自己調整了執行緒數,直到maxThreads的值。然後執行緒的空閒狀態就越來越少,到最後幾乎沒有空閒狀態了。

你也可以看到響應時間隨著執行緒數的不夠用而不斷的增加。

這就是典型的執行緒配置不夠的狀態

場景三:當壓力執行緒數遠高於服務端執行緒數時


測試結果:

summary +      1 in 00:00:02 =    0.5/s Avg:  1724 Min:  1724 Max:  1724 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary +   5821 in 00:00:28 =  204.3/s Avg:   128 Min:     1 Max:  1798 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =   5822 in 00:00:31 =  190.8/s Avg:   129 Min:     1 Max:  1798 Err:     0 (0.00%)
summary +  10881 in 00:00:30 =  362.7/s Avg:    57 Min:     1 Max:   405 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  16703 in 00:01:01 =  276.0/s Avg:    82 Min:     1 Max:  1798 Err:     0 (0.00%)
summary +  11548 in 00:00:30 =  384.9/s Avg:    52 Min:     1 Max:   308 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  28251 in 00:01:31 =  312.1/s Avg:    70 Min:     1 Max:  1798 Err:     0 (0.00%)
summary +   3747 in 00:00:10 =  387.8/s Avg:    51 Min:     1 Max:   328 Err:     0 (0.00%) Active: 0 Started: 50 Finished: 50
summary =  31998 in 00:01:40 =  319.4/s Avg:    67 Min:     1 Max:  1798 Err:     0 (0.00%)

執行緒監控結果:

在這個壓力場景中,我直接把壓力執行緒加上來,並且高於Tomcat的處理執行緒,Tomcat一下就上到了maxThreads的上限,然後就幾乎沒再閒過。同時你也可以看到響應時間遠遠大於場景二中的響應時間。

這就是典型的壓力過高的狀態

對比前面三個場景,我們再比對之前專欄中的文章內容,就可以理解幾個關鍵的知識點了。

首先,壓力工具中的執行緒數到底應不應該在沒有報錯的情況下無休止地增加?

顯然即使你增加,對服務端能處理的請求來說,並沒有什麼意義,只會導致響應時間的變長。

其次,把壓力執行緒理解為併發使用者數到底對不對?

如果你把壓力執行緒理解為併發使用者,通過這幾個示例就可以看到,服務端能處理的壓力執行緒必然不會超過自身的執行緒上限,也就是說,把壓力執行緒理解為併發使用者,併發使用者的上限是固定的。你都不用測試,直接看服務端的執行緒數配置為多大就夠了。這也是為什麼我一再強調併發使用者數不能用壓力執行緒來描述,不能用壓力執行緒來承載服務端效能指標的關鍵點。

而用TPS來描述的時候,因為有了“秒”的概念,就有了時間段,而在這個時間段內得到的響應都認為是被支援了的,所以用TPS來描述會更為合理。
而T的定義具有業務含義時,也就對應起了技術和業務之間的關係,這個邏輯也就完整了。

從這裡你也可以看到,我在整個專欄中所描述的概念在具體的落地時,都會秉承它的連貫性,要不然一個飛在空中的概念就沒有意義了。

場景四:設定最大最小空閒執行緒數


測試結果:

summary +      1 in 00:00:01 =    0.9/s Avg:   730 Min:   730 Max:   730 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   2915 in 00:00:30 =   97.5/s Avg:     5 Min:     0 Max:  1126 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary =   2916 in 00:00:31 =   94.1/s Avg:     5 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +   6690 in 00:00:30 =  222.9/s Avg:     4 Min:     0 Max:    81 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =   9606 in 00:01:01 =  157.5/s Avg:     4 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +   9968 in 00:00:30 =  332.4/s Avg:     4 Min:     0 Max:    88 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  19574 in 00:01:31 =  215.2/s Avg:     4 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  14140 in 00:00:30 =  471.1/s Avg:     3 Min:     0 Max:    87 Err:     0 (0.00%) Active: 7 Started: 7 Finished: 0
summary =  33714 in 00:02:01 =  278.6/s Avg:     4 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  14985 in 00:00:30 =  499.8/s Avg:     4 Min:     0 Max:    84 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  48699 in 00:02:31 =  322.6/s Avg:     4 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  16446 in 00:00:30 =  548.1/s Avg:     4 Min:     0 Max:    76 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary =  65145 in 00:03:01 =  360.0/s Avg:     4 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  16171 in 00:00:30 =  539.2/s Avg:     5 Min:     0 Max:   410 Err:     0 (0.00%) Active: 11 Started: 11 Finished: 0
summary =  81316 in 00:03:31 =  385.4/s Avg:     4 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  16419 in 00:00:30 =  547.2/s Avg:     7 Min:     0 Max:   646 Err:     0 (0.00%) Active: 13 Started: 13 Finished: 0
summary =  97735 in 00:04:01 =  405.6/s Avg:     5 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  15981 in 00:00:30 =  532.7/s Avg:     9 Min:     0 Max:   832 Err:     0 (0.00%) Active: 14 Started: 14 Finished: 0
summary = 113716 in 00:04:31 =  419.7/s Avg:     5 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  16064 in 00:00:30 =  535.6/s Avg:    11 Min:     0 Max:   888 Err:     0 (0.00%) Active: 16 Started: 16 Finished: 0
summary = 129780 in 00:05:01 =  431.2/s Avg:     6 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  15446 in 00:00:30 =  514.8/s Avg:    10 Min:     0 Max:  1022 Err:     0 (0.00%) Active: 17 Started: 17 Finished: 0
summary = 145226 in 00:05:31 =  438.8/s Avg:     6 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  14643 in 00:00:30 =  488.1/s Avg:    12 Min:     0 Max:  1114 Err:     0 (0.00%) Active: 19 Started: 19 Finished: 0
summary = 159869 in 00:06:01 =  442.9/s Avg:     7 Min:     0 Max:  1126 Err:     0 (0.00%)
summary +  14805 in 00:00:30 =  493.5/s Avg:    13 Min:     0 Max:  1250 Err:     0 (0.00%) Active: 20 Started: 20 Finished: 0
summary = 174674 in 00:06:31 =  446.8/s Avg:     7 Min:     0 Max:  1250 Err:     0 (0.00%)
summary +  14446 in 00:00:30 =  481.5/s Avg:    15 Min:     0 Max:  1385 Err:     0 (0.00%) Active: 22 Started: 22 Finished: 0
summary = 189120 in 00:07:01 =  449.2/s Avg:     8 Min:     0 Max:  1385 Err:     0 (0.00%)
summary +  14310 in 00:00:30 =  477.1/s Avg:    17 Min:     0 Max:  1454 Err:     0 (0.00%) Active: 23 Started: 23 Finished: 0
summary = 203430 in 00:07:31 =  451.1/s Avg:     9 Min:     0 Max:  1454 Err:     0 (0.00%)
summary +  13856 in 00:00:30 =  461.8/s Avg:    18 Min:     0 Max:  1454 Err:     0 (0.00%) Active: 25 Started: 25 Finished: 0
summary = 217286 in 00:08:01 =  451.8/s Avg:     9 Min:     0 Max:  1454 Err:     0 (0.00%)
summary +  13643 in 00:00:30 =  454.8/s Avg:    18 Min:     0 Max:  1591 Err:     0 (0.00%) Active: 26 Started: 26 Finished: 0
summary = 230929 in 00:08:31 =  451.9/s Avg:    10 Min:     0 Max:  1591 Err:     0 (0.00%)
summary +  13605 in 00:00:30 =  453.5/s Avg:    21 Min:     0 Max:  1593 Err:     0 (0.00%) Active: 28 Started: 28 Finished: 0
summary = 244534 in 00:09:01 =  452.0/s Avg:    10 Min:     0 Max:  1593 Err:     0 (0.00%)
summary +  13316 in 00:00:30 =  443.7/s Avg:    23 Min:     0 Max:  1598 Err:     0 (0.00%) Active: 29 Started: 29 Finished: 0
summary = 257850 in 00:09:31 =  451.6/s Avg:    11 Min:     0 Max:  1598 Err:     0 (0.00%)
summary +  12538 in 00:00:30 =  418.1/s Avg:    24 Min:     0 Max:  1599 Err:     0 (0.00%) Active: 30 Started: 30 Finished: 0
summary = 270388 in 00:10:01 =  449.9/s Avg:    12 Min:     0 Max:  1599 Err:     0 (0.00%)

執行緒監控結果:

這個場景是為了描述minSpareThreads和maxSpareThreads的能力,我們可以看到場景結束了之後,執行緒確實被回收了。

記住,這個回收的價值在於,當再次有少量請求進來時不會導致過多的維護執行緒的成本,從而導致TPS的下降。如果你的應用中,本身執行緒數就不是非常大,即使長時間維護著固定的執行緒池也不會有大的成本,那麼不配置這兩個引數也是可以的。

禁用AJP

什麼是AJP呢?你可以點選這裡看一下。

AJP是個二進位制的TCP傳輸協議,相比HTTP來說有更高的效能和效率,只是支援AJP的代理伺服器不多。在我們常用的應用場景中,用Nginx來連線Tomcat較多,AJP協議是用不上的,因為Nginx官方根本就沒有支援AJP協議的模組。當然也有人提供過AJP的Nginx代理模組,只是實際應用的也不多。

下面我們看禁用AJP和啟用AJP產生的效果。

首先看下啟用AJP的測試結果。

啟動AJP(在Tomcat的conf/server.xml中配置):

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

啟動日誌:

21-Jan-2020 01:14:58.404 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [ajp-nio-8009]

測試結果為下面這樣:

summary +      4 in 00:00:02 =    1.8/s Avg:   482 Min:   188 Max:   903 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   2704 in 00:00:29 =   92.8/s Avg:     5 Min:     0 Max:    83 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary =   2708 in 00:00:31 =   86.4/s Avg:     5 Min:     0 Max:   903 Err:     0 (0.00%)
summary +   6154 in 00:00:30 =  205.1/s Avg:     4 Min:     0 Max:    89 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =   8862 in 00:01:01 =  144.5/s Avg:     5 Min:     0 Max:   903 Err:     0 (0.00%)
summary +   8818 in 00:00:30 =  293.9/s Avg:     4 Min:     0 Max:    71 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =  17680 in 00:01:31 =  193.6/s Avg:     4 Min:     0 Max:   903 Err:     0 (0.00%)
summary +  13267 in 00:00:30 =  442.3/s Avg:     4 Min:     0 Max:    66 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  30947 in 00:02:01 =  255.0/s Avg:     4 Min:     0 Max:   903 Err:     0 (0.00%)
summary +  13004 in 00:00:30 =  433.4/s Avg:     4 Min:     0 Max:    59 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =  43951 in 00:02:31 =  290.4/s Avg:     4 Min:     0 Max:   903 Err:     0 (0.00%)
summary +  15800 in 00:00:30 =  526.6/s Avg:     4 Min:     0 Max:    88 Err:     0 (0.00%) Active: 7 Started: 7 Finished: 0
summary =  59751 in 00:03:01 =  329.5/s Avg:     4 Min:     0 Max:   903 Err:     0 (0.00%)
summary +  16766 in 00:00:30 =  559.0/s Avg:     5 Min:     0 Max:    90 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  76517 in 00:03:31 =  362.1/s Avg:     4 Min:     0 Max:   903 Err:     0 (0.00%)
summary +  16760 in 00:00:30 =  558.6/s Avg:     5 Min:     0 Max:    67 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary =  93277 in 00:04:01 =  386.5/s Avg:     4 Min:     0 Max:   903 Err:     0 (0.00%)
summary +  16991 in 00:00:30 =  566.4/s Avg:     6 Min:     0 Max:   148 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 110268 in 00:04:31 =  406.4/s Avg:     5 Min:     0 Max:   903 Err:     0 (0.00%)

然後我們再看下禁用AJP的測試結果。

禁用AJP:

<!-- Connector port="8009" protocol="AJP/1.3" redirectPort="8443" -->

無啟動日誌。

測試結果:

summary +     90 in 00:00:05 =   16.9/s Avg:    33 Min:     2 Max:   812 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   3443 in 00:00:30 =  115.0/s Avg:     4 Min:     0 Max:    93 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary =   3533 in 00:00:35 =  100.2/s Avg:     5 Min:     0 Max:   812 Err:     0 (0.00%)
summary +   7245 in 00:00:30 =  241.5/s Avg:     4 Min:     0 Max:    75 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =  10778 in 00:01:05 =  165.2/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)
summary +  11029 in 00:00:30 =  367.6/s Avg:     4 Min:     0 Max:   335 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =  21807 in 00:01:35 =  228.9/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)
summary +  12227 in 00:00:30 =  407.5/s Avg:     4 Min:     0 Max:    67 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  34034 in 00:02:05 =  271.7/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)
summary +  14735 in 00:00:30 =  491.4/s Avg:     4 Min:     0 Max:    72 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =  48769 in 00:02:35 =  314.1/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)
summary +  16574 in 00:00:30 =  552.5/s Avg:     4 Min:     0 Max:    65 Err:     0 (0.00%) Active: 7 Started: 7 Finished: 0
summary =  65343 in 00:03:05 =  352.7/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)
summary +  17488 in 00:00:30 =  582.9/s Avg:     4 Min:     0 Max:    70 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  82831 in 00:03:35 =  384.8/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)
summary +  16933 in 00:00:30 =  564.5/s Avg:     5 Min:     0 Max:    87 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary =  99764 in 00:04:05 =  406.8/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)
summary +  17363 in 00:00:30 =  578.8/s Avg:     6 Min:     0 Max:    76 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 117127 in 00:04:35 =  425.5/s Avg:     4 Min:     0 Max:   812 Err:     0 (0.00%)

通過比對,如下圖所示:

禁用AJP確實性能會高一點,在這個場景中最高的時候,同壓力執行緒下,效能高出近20%。

壓縮

在很多的壓力測試中,我們說壓縮這個功能都是基於兩個目標:

  1. 減少頻寬的消耗;
  2. 減少傳輸的時間;

但是這必然會導致服務端CPU消耗的增加,這是個必然的過程。所以它的配置前提就是CPU足夠用,頻寬不夠用。如果你頻寬足夠用,CPU不夠用時,顯然這樣做是不理智的。

下面我們來看一下Tomcat中壓縮和不壓縮產生的結果。

首先是不壓縮。

summary +    588 in 00:00:13 =   46.0/s Avg:    10 Min:     1 Max:   804 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   4403 in 00:00:30 =  146.8/s Avg:     4 Min:     0 Max:    87 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary =   4991 in 00:00:43 =  116.7/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)
summary +   7107 in 00:00:30 =  237.1/s Avg:     4 Min:     0 Max:    77 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =  12098 in 00:01:13 =  166.3/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  11121 in 00:00:30 =  370.7/s Avg:     4 Min:     0 Max:    72 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =  23219 in 00:01:43 =  226.0/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  12709 in 00:00:30 =  423.6/s Avg:     4 Min:     0 Max:    87 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  35928 in 00:02:13 =  270.6/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  14548 in 00:00:30 =  485.0/s Avg:     4 Min:     0 Max:    69 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =  50476 in 00:02:43 =  310.1/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  15810 in 00:00:30 =  527.0/s Avg:     5 Min:     0 Max:    83 Err:     0 (0.00%) Active: 7 Started: 7 Finished: 0
summary =  66286 in 00:03:13 =  343.9/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  15242 in 00:00:30 =  508.0/s Avg:     5 Min:     0 Max:    77 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  81528 in 00:03:43 =  366.0/s Avg:     4 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  16709 in 00:00:30 =  557.1/s Avg:     5 Min:     0 Max:    75 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary =  98237 in 00:04:13 =  388.7/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)
summary +  17099 in 00:00:30 =  570.0/s Avg:     6 Min:     0 Max:   161 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 115336 in 00:04:43 =  407.9/s Avg:     5 Min:     0 Max:   804 Err:     0 (0.00%)

網路流量:

然後是壓縮。

在這裡,我為了讓壓縮生效的範圍更大,把最小值設定為了10bytes。

compression="on" compressionMinSize="10" noCompressionUserAgents="gozilla,traviata" compressableMimeType="text/html,text/xml,application/javascript,text/javascript,text/css,text/plain,text/json"

summary +   1037 in 00:00:09 =  117.5/s Avg:     4 Min:     0 Max:   418 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +   5832 in 00:00:30 =  194.2/s Avg:     3 Min:     0 Max:    74 Err:     0 (0.00%) Active: 2 Started: 2 Finished: 0
summary =   6869 in 00:00:39 =  176.8/s Avg:     3 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  10378 in 00:00:30 =  346.3/s Avg:     3 Min:     0 Max:    71 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =  17247 in 00:01:09 =  250.6/s Avg:     3 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  12670 in 00:00:30 =  422.2/s Avg:     3 Min:     0 Max:    64 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =  29917 in 00:01:39 =  302.7/s Avg:     3 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  13917 in 00:00:30 =  464.0/s Avg:     4 Min:     0 Max:    78 Err:     0 (0.00%) Active: 5 Started: 5 Finished: 0
summary =  43834 in 00:02:09 =  340.3/s Avg:     3 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  14815 in 00:00:30 =  493.9/s Avg:     4 Min:     0 Max:    79 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =  58649 in 00:02:39 =  369.3/s Avg:     3 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  15710 in 00:00:30 =  523.6/s Avg:     5 Min:     0 Max:    89 Err:     0 (0.00%) Active: 7 Started: 7 Finished: 0
summary =  74359 in 00:03:09 =  393.8/s Avg:     4 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  16059 in 00:00:30 =  535.3/s Avg:     5 Min:     0 Max:    70 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =  90418 in 00:03:39 =  413.2/s Avg:     4 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  15909 in 00:00:30 =  530.2/s Avg:     6 Min:     0 Max:    96 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary = 106327 in 00:04:09 =  427.3/s Avg:     4 Min:     0 Max:   418 Err:     0 (0.00%)
summary +  16011 in 00:00:30 =  533.8/s Avg:     6 Min:     0 Max:    75 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 122338 in 00:04:39 =  438.8/s Avg:     4 Min:     0 Max:   418 Err:     0 (0.00%)

網路流量:

通過上面的測試比對結果可以看到:

確實在CPU資源足夠用的時候,採用壓縮,TPS要大一些,但隨著壓力的增加,CPU資源不夠了之後,壓縮就沒啥用了。

從頻寬傳輸上可以看到,不壓縮時最大頻寬達到40M,而壓縮時最大頻寬只有14M,可見壓縮對頻寬的作用還是很顯著的。

acceptCount

在上面的思維導圖中,執行緒池最後一個引數就是acceptCount,這個值就比較容易理解,就是TCP的接收佇列長度。

這次我直接用一個大壓力的場景說明它的值大小的區別。我直接上50個執行緒。為什麼要這麼做呢,就是為了讓佇列產生得多一些。

下面我們直接來看結果吧。

acceptCount=“10000”

測試結果:

summary +   2400 in 00:00:11 =  217.6/s Avg:   108 Min:     3 Max:  1176 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary +  10322 in 00:00:30 =  344.1/s Avg:    62 Min:     1 Max:   470 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  12722 in 00:00:41 =  310.1/s Avg:    71 Min:     1 Max:  1176 Err:     0 (0.00%)
summary +  12660 in 00:00:30 =  422.0/s Avg:    49 Min:     0 Max:   331 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  25382 in 00:01:11 =  357.4/s Avg:    60 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  13337 in 00:00:30 =  444.6/s Avg:    46 Min:     1 Max:   410 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  38719 in 00:01:41 =  383.3/s Avg:    55 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  14176 in 00:00:30 =  472.4/s Avg:    43 Min:     0 Max:   302 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  52895 in 00:02:11 =  403.7/s Avg:    52 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  14696 in 00:00:30 =  489.7/s Avg:    42 Min:     1 Max:   261 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  67591 in 00:02:41 =  419.7/s Avg:    50 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  16191 in 00:00:30 =  539.9/s Avg:    38 Min:     0 Max:   320 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  83782 in 00:03:11 =  438.6/s Avg:    47 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +   5299 in 00:00:09 =  580.1/s Avg:    36 Min:     1 Max:   201 Err:     0 (0.00%) Active: 0 Started: 50 Finished: 50
summary =  89081 in 00:03:20 =  445.0/s Avg:    47 Min:     0 Max:  1176 Err:     0 (0.00%)

acceptCount=“100”

測試結果:

summary +   1115 in 00:00:11 =  100.1/s Avg:   306 Min:    11 Max:  1936 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary +   7923 in 00:00:30 =  264.1/s Avg:    87 Min:     1 Max:   521 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =   9038 in 00:00:41 =  219.7/s Avg:   114 Min:     1 Max:  1936 Err:     0 (0.00%)
summary +  11414 in 00:00:30 =  380.5/s Avg:    56 Min:     1 Max:   381 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  20452 in 00:01:11 =  287.5/s Avg:    81 Min:     1 Max:  1936 Err:     0 (0.00%)
summary +  11949 in 00:00:30 =  398.4/s Avg:    51 Min:     0 Max:   390 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  32401 in 00:01:41 =  320.4/s Avg:    70 Min:     0 Max:  1936 Err:     0 (0.00%)
summary +  13403 in 00:00:30 =  446.7/s Avg:    46 Min:     0 Max:   326 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  45804 in 00:02:11 =  349.3/s Avg:    63 Min:     0 Max:  1936 Err:     0 (0.00%)
summary +  13271 in 00:00:30 =  442.4/s Avg:    45 Min:     0 Max:   295 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  59075 in 00:02:41 =  366.6/s Avg:    59 Min:     0 Max:  1936 Err:     0 (0.00%)
summary +  14307 in 00:00:30 =  476.9/s Avg:    43 Min:     1 Max:   288 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  73382 in 00:03:11 =  383.9/s Avg:    56 Min:     0 Max:  1936 Err:     0 (0.00%)
summary +   4292 in 00:00:09 =  476.3/s Avg:    42 Min:     1 Max:   226 Err:     0 (0.00%) Active: 0 Started: 50 Finished: 50
summary =  77674 in 00:03:20 =  388.1/s Avg:    55 Min:     0 Max:  1936 Err:     0 (0.00%)

通過上面的結果,可以得到下圖:

可見當acceptCount大時,對TPS還是有明顯幫助的。

接下來,我們再看下connectionTimeout。

connectionTimeout

我需要說明的是,以下場景均基於以下配置:acceptCount=“10000”。

這個值對我們來說,也是非常關鍵的資料,因為它影響著KeepAlive的超時和connection的超時。

我們在效能分析的時候,會遇到一種情況是,很多應用都用預設超時,而在壓力大的時候,會有少量的報錯是因為前端的超時已經到了,而後端還沒到,因為畢竟後端是後接收到的請求。這就導致了大壓力下少量的錯誤是因為超時配置導致的。

所以我們通常都會畫一個圖如下所示:

而在真實的應用場景中,應該配置多長時間的超時一定是經過嚴格的測試的。

下面我們來看看結果。

connectionTimeout="20000"時,這個結果直接拿上面的測試結果複用。

測試結果:

summary +   2400 in 00:00:11 =  217.6/s Avg:   108 Min:     3 Max:  1176 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary +  10322 in 00:00:30 =  344.1/s Avg:    62 Min:     1 Max:   470 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  12722 in 00:00:41 =  310.1/s Avg:    71 Min:     1 Max:  1176 Err:     0 (0.00%)
summary +  12660 in 00:00:30 =  422.0/s Avg:    49 Min:     0 Max:   331 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  25382 in 00:01:11 =  357.4/s Avg:    60 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  13337 in 00:00:30 =  444.6/s Avg:    46 Min:     1 Max:   410 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  38719 in 00:01:41 =  383.3/s Avg:    55 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  14176 in 00:00:30 =  472.4/s Avg:    43 Min:     0 Max:   302 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  52895 in 00:02:11 =  403.7/s Avg:    52 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  14696 in 00:00:30 =  489.7/s Avg:    42 Min:     1 Max:   261 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  67591 in 00:02:41 =  419.7/s Avg:    50 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +  16191 in 00:00:30 =  539.9/s Avg:    38 Min:     0 Max:   320 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  83782 in 00:03:11 =  438.6/s Avg:    47 Min:     0 Max:  1176 Err:     0 (0.00%)
summary +   5299 in 00:00:09 =  580.1/s Avg:    36 Min:     1 Max:   201 Err:     0 (0.00%) Active: 0 Started: 50 Finished: 50
summary =  89081 in 00:03:20 =  445.0/s Avg:    47 Min:     0 Max:  1176 Err:     0 (0.00%)

當connectionTimeout="200"時,測試結果為:

summary +   1540 in 00:00:13 =  117.5/s Avg:   258 Min:     7 Max:  2150 Err:    15 (0.97%) Active: 50 Started: 50 Finished: 0
summary +  10080 in 00:00:30 =  336.4/s Avg:    65 Min:     1 Max:   465 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  11620 in 00:00:43 =  269.8/s Avg:    90 Min:     1 Max:  2150 Err:    15 (0.13%)
summary +  12691 in 00:00:30 =  422.8/s Avg:    49 Min:     0 Max:   317 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  24311 in 00:01:13 =  332.6/s Avg:    69 Min:     0 Max:  2150 Err:    15 (0.06%)
summary +  12707 in 00:00:30 =  423.8/s Avg:    48 Min:     1 Max:   312 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  37018 in 00:01:43 =  359.2/s Avg:    62 Min:     0 Max:  2150 Err:    15 (0.04%)
summary +  13530 in 00:00:30 =  450.7/s Avg:    45 Min:     0 Max:   306 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  50548 in 00:02:13 =  379.8/s Avg:    57 Min:     0 Max:  2150 Err:    15 (0.03%)
summary +  13791 in 00:00:30 =  460.0/s Avg:    44 Min:     1 Max:   344 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  64339 in 00:02:43 =  394.5/s Avg:    55 Min:     0 Max:  2150 Err:    15 (0.02%)
summary +  14840 in 00:00:30 =  494.6/s Avg:    41 Min:     0 Max:   319 Err:     0 (0.00%) Active: 50 Started: 50 Finished: 0
summary =  79179 in 00:03:13 =  410.1/s Avg:    52 Min:     0 Max:  2150 Err:    15 (0.02%)
summary +   3734 in 00:00:07 =  530.5/s Avg:    39 Min:     1 Max:   282 Err:     0 (0.00%) Active: 0 Started: 50 Finished: 50
summary =  82913 in 00:03:20 =  414.3/s Avg:    51 Min:     0 Max:  2150 Err:    15 (0.02%)

看到沒有,一開始就有少量的報錯產生了,但一些我沒加斷言的報錯應該沒有在這裡沒顯示出來。

所以根據應用的重要性,超時長度在具體的應用場景中,一定要做嚴格的測試。把完整的業務鏈路圖畫出來之後,一個個環節分析超時應該設定為多大,才是合理的做法。

總結

至於其他的Tomcat調優引數,你可以在自己的場景中實際操作一下。

總之,Tomcat的優化就是這麼幾個關鍵環節:協議、執行模式(儘管現在我認為它已經不再有爭議了,但是當你用老版本的Tomcat時還是要注意一下)、執行緒池(關鍵中的關鍵)等。

不止是Tomcat這樣,其他類似的應用伺服器也是一樣。儘管這些應用伺服器在架構設計上會不同,但是在我的調優生涯中,針對這樣的應用伺服器,可調優的關鍵點真的就這麼幾個。

可見這樣的應用伺服器本身可調優的點並不多。如果你要調的是SpringBoot中的Tomcat元件,也可以用同樣的思路。

最後我還是要說,在你的具體工作中,一定要拿實際測試結果來分析判斷,以免產生偏差。在任何時候,都要知道,效能測試的計數器中,沒有哪個計數器的值可以直接告訴你效能問題的原因,只有通過自己的分析判斷才能找得到。