看到一篇關於最佳執行緒數相關的文章,內容比較經典,不敢私藏,分享一下!
最佳執行緒數:
效能壓測的情況下,起初隨著使用者數的增加,QPS會上升,當到了一定的閥值之後,使用者數量增加QPS並不會增加,或者增加不明顯,同時請求的響應時間卻大幅增加。這個閥值我們認為是最佳執行緒數。
為什麼要找最佳執行緒數
1.過多的執行緒只會造成,更多的記憶體開銷,更多的CPU開銷,但是對提升QPS確毫無幫助
2.找到最佳執行緒數後通過簡單的設定,可以讓web系統更加穩定,得到最高,最穩定的QPS輸出
最佳執行緒數的獲取:
1、通過使用者慢慢遞增來進行效能壓測,觀察QPS,響應時間
2、根據公式計算:伺服器端最佳執行緒數量=((執行緒等待時間+執行緒cpu時間)/執行緒cpu時間) * cpu數量
3、單使用者壓測,檢視CPU的消耗,然後直接乘以百分比,再進行壓測,一般這個值的附近應該就是最佳執行緒數量。
影響最佳執行緒數的主要因素:
1、IO
2、CPU
根據公式:伺服器端最佳執行緒數量=((執行緒等待時間+執行緒cpu時間)/執行緒cpu時間) * cpu數量
一般來說是IO和CPU。IO開銷較多的應用其CPU執行緒等待時間會比較長,所以執行緒數量可以開的多一些,相反則執行緒數量要少一些,其實有兩種極端,純IO的應用,比如proxy,則執行緒數量可以開到非常大(實在太大了則需要考慮執行緒切換的開銷),這種應用基本上後端(比如這個proxy是代理搜尋的)的QPS能有多少,proxy就有多少。
另一種是耗CPU的計算,這種情況一般來講只能開到CPU個數的執行緒數量。但是並不是說這種應用的QPS就不高,往往這種應用的QPS可以很高。
QPS和執行緒數的關係
1、在最佳執行緒數量之前,QPS和執行緒是互相遞增的關係,執行緒數量到了最佳執行緒之後,QPS持平,不在上升,甚至略有下降,同時相應時間持續上升。
2、同一個系統而言,支援的執行緒數越多(最佳執行緒數越多而不是配置的執行緒數越多),QPS越高
QPS和響應時間的關係
1、對於一般的web系統,響應時間一般有CPU執行時間+IO等待時間組成
2、CPU的執行時間減少,對QPS有實質的提升,IO時間的減少,對QPS提升不明顯。如果要想明顯提升QPS,優化系統的時候要著重優化CPU消耗大戶。
最佳執行緒數和jvm堆記憶體得關係:
以上都是依據效能瓶頸在CPU的情況,對於java應用還有一個因素是FULL GC,我們要保證在最佳執行緒數量下,不會發生頻繁FULL GC
根據公式::(小GC時間間隔/rt)*(併發執行緒數量 * thm) <=young 計算得到的併發執行緒數量如果<最佳執行緒數量 則可能導致FULL GC較頻繁,實際情況看來這種情況在web系統上非常少。不過可以模擬出來。
所以我們在設定jboss執行緒的時候,可以利用記憶體公式計算出來的執行緒數量來設定,通過壓測和計算得到最佳執行緒數,然後設定執行緒數。
設定執行緒數量:
壓測最佳執行緒數<真實設定的執行緒數量<記憶體極限執行緒數
比如,通過壓測得到某系統的最佳執行緒數量是10,然後通過記憶體計算的執行緒數量是20,則,設定jboss的執行緒數量為15是可行的,如果直接設定了10,由於系統本身會受到一些依賴系統的變化而產生一些變化,比如系統依賴一些IO的響應時間會突然延長,由於執行緒數量還是10,其實這個時候最佳執行緒數量已經變成了13了,由於我們設定死了10,其結果就是導致qps下降,但是如果超過20,則又會引起FULL gc非常頻繁,反過來影響QPS的下降。
jboss的執行緒數設定:
對於jboss而言,設定執行緒數量要看使用了那種執行緒連線,如http、ajp等
http和ajp的設定是完全一樣的,非常簡單:
以ajp為例,找到server.xml或者tomcat-server.xml:
預設執行緒數量是200個
<Connector port="8009" address="${jboss.bind.address}" connectionTimeout="15000" protocol="AJP/1.3" maxThreads="200" minSpareThreads="40" maxSpareThreads="75" maxPostSize="512000" acceptCount="300" bufferSize="16384" emptySessionPath="false" enableLookups="false" redirectPort="8443" useBodyEncodingForURI="true"/>
這裡將預設的執行緒數量改成了20,當然相應的其他最小空閒執行緒數和最大空閒執行緒數也做一下調整:
<Connector port="8009" address="${jboss.bind.address}" connectionTimeout="15000" protocol="AJP/1.3" maxThreads="20" minSpareThreads="20" maxSpareThreads="20" maxPostSize="512000" acceptCount="300" bufferSize="16384" emptySessionPath="false" enableLookups="false" redirectPort="8443" useBodyEncodingForURI="true"/>