1.簡介
JSF業務線程池使用JDK的線程池技術,缺省情況下采用Cached模式(核心線程數20,最大線程數200)。此外,還提供了Fixed固定線程大小的模式,兩種模式均可設置請求隊列大小。
本文旨在通過一個簡化場景(“單服務應用”)下的負載測試,為“JSF業務線程池大小配置”提供基準測試結果,並形成一些普遍適用的結論。
本文的目標讀者包括需要合理配置JSF線程大小的壓測工程師、開發部署運維工程師以及架構師。本文不涉及JSF服務端的其他配置項,也不針對“複合服務應用”的合理配置進行探討。你可以利用本文提供的結論,作為設計壓測用例或評估業務線程池大小的基本方法的參考,以便在實踐中合理配置JSF業務線程池大小。需要注意的是,JSF業務線程池大小的合理配置應該基於高保真的負載測試結果。
“單服務應用”指應用僅包含一個提供接口,且接口中僅有一個方法。
“複合服務應用”則指應用包含多個提供接口或一個接口中含有多個方法。
2.測試用例説明
本次基準測試選取了USF3.0權限系統,將其定製化為一個單一的服務提供者,僅對該提供者的一個方法進行了測試,因此可以看作是一個“單服務應用”。測試中將CPU作為基準測試的核心資源,並考慮到JVM垃圾收集器的影響,採用了簡單的測試數據以保證服務每次調用的一致性,並確保YGC具有規律性(即固定調用量會導致一次30+ms的YGC),無FGC的影響。
測試用例的設計中,所有依賴的服務資源都無限制,以確保測試過程中服務的可用率達到100%。我們的關鍵性能指標是TP99,即服務響應時長的99%必須小於10ms。
為了測試不同線程池模式下的性能表現,我們使用了JSF線程池的Cached和Fixed兩種模式,並針對每種模式進行了多組測試,以得出在滿足TP99<10ms的前提下,系統最大的負載情況。
測試應用:USF3.0權限系統(定製化處理)
測試服務:com.jd.susf.service.api.SusfPermissionService#findUserInfo,根據用户信息從Redis中查詢一條數據返回的服務。
硬件配置:單台4C 8G
測試方法:在Forcebot系統採用了階梯發壓的方式對JSF業務線程池在Cached和Fixed模式下進行了系統負載測試
擬定SLA要求:服務響應時長的TP99<10ms
注:我們對USF3.0權限系統進行了定製,調整了服務提供方的配置數據,僅保留了 com.jd.susf.service.api.SusfPermissionService。
3.測試結果及分析
3.1.cached線程池的系統負載
圖:JSF默認線程池(cached, threads=200)在不同併發用户數(1-200)下的系統負載圖
| 併發用户數 | TP99 | 吞吐量TPS | CPU利用率(%) |
|---|---|---|---|
| 1~23 | <8ms | 線性增長 | 線性增長 |
| 24 | 8ms | 6553 | 99.62 |
| 25 | 11ms | 6607 | 99.83 |
| 26~79 | 迅速增長 | 緩慢增長 | 99+ |
| 80 | 74ms | 6928 | 99.82 |
| 81~199 | 緩慢增加 | 緩慢下降 | 99.82 |
| 200 | 99ms | 6230 | 99.94 |
小結:默認的JSF線程池配置存在很大的風險。系統最大可支持24個併發,超過24個併發SLA就無法滿足。
3.2 fixed線程池(隊列)的系統負載
圖:JSF固定線程池(fixed+隊列)在不同併發用户數(1-50)下的系統負載圖
| JSF業務線程數 | 可支持的最大併發用户數 | TP值(50/90/99/999) | 吞吐量(TPS) | CPU最大利用率(%) |
|---|---|---|---|---|
| 4 | 11 | 7/8/10/18 | 1531 | 27.67 |
| 8 | 25 | 8/8/10/18 | 3113 | 46.45 |
| 16 | 50 | 8/8/10/21 | 6228 | 87.97 |
| 20 | 23 | 3/4/10/15 | 6409 | 99.92 |
| 24 | 22 | 3/4/7/15 | 6178 | 99.86 |
| 25 | 22 | 3/4/6/15 | 6182 | 98.83 |
表:JSF固定業務線程池(fixed+隊列)在滿足TP99<10ms的系統最大負載(最大併發用户數)
小結:
① 在fixed線程模式下,CPU的利用率存在使用上限。
② 隊列的使用可以有效增加系統對併發量的支持,同時也會帶來吞吐量的提升。然而,由於任務在隊列中等待,服務的響應時間會出現“水漲船高”的現象,存在一定風險。
3.3 fixed線程池的系統負載
圖:JSF固定線程池(fixed)模式下,系統最大併發用户數時的系統負載
| JSF業務線程數 | 併發用户數 | TP99 | 吞吐量(TPS) | CPU最大利用率(%) |
|---|---|---|---|---|
| 4 | 4 | 5 | 1063 | 20.26 |
| 8 | 8 | 5 | 2216 | 36.62 |
| 16 | 16 | 6 | 4262 | 68.56 |
| 20 | 20 | 5 | 5550 | 86.22 |
| 24 | 24 | 8 | 6711 | 99.62 |
| 25 | 25 | 16 | 6644 | 98.77 |
| 26 | 26 | 19 | 6744 | 99.93 |
小結:綜合固定線程池(fixed)的性能表現,需要設置一個合理的線程數大小來平衡CPU資源的充分利用和滿足SLA的需求,線程數過小會導致CPU資源浪費,線程數過大則無法滿足SLA
4.結論
根據測試結果和數據分析,我們得出以下結論:
- JSF線程池的默認配置在併發量高的場景下存在風險:所有線上生產環境中的JSF服務所在的服務器,很少有能夠在200個線程的情況下還能夠滿足SLA的。最大200個線程的線程池配置,將服務器置於“併發量高的場景下被壓垮”的風險中。線程池大小的合理配置應該來自高保真的負載測試。
- 足量的線程數才能保證資源(CPU)的利用率:業務型的服務通常都存在一定的IO操作(網絡,磁盤等),線程執行過程中會發生等待,CPU利用率不高,需要增加併發的線程數量,讓更多的線程參與CPU的分配,才能提高CPU的利用率。服務中IO操作越多,等待時長越長,需要的併發線程就越多。對於有IO操作的業務型服務,負載測試的線程數可以從2N(N是服務器的CPU核數)開始。
- 過多的線程數只會降低系統的SLA:當線程數已能100%利用CPU後,增加線程數,線程就無法獲取足夠的CPU分配,這樣服務的響應時間就會增大。在一定範圍內,TP99還可能滿足SLA的要求,系統的吞吐量也會有少量的增加。再持續增加線程數,TP99就無法滿足系統的要求,系統的吞吐量也會開始下降。
- 固定的線程數可以保護系統需要承擔的負載能力:固定線程數可以保證系統對CPU的利用率限定在一定的負載範圍內,保護系統穩定運行,保證響應時間TP99,但也限定了系統的併發能力。合理設置隊列大小可以增加系統的併發度,也不會影響系統TP99,但會整體拉高服務的響應時間,出現不穩定性的變化,存在風險。
- 讓CPU100%的高負載運行:通常服務對外的SLA承諾通常高於服務真實的性能,這是因為我們考慮了基礎設施及依賴服務的不穩定性。因此,即使CPU已經達到了100%,我們仍然可以增加一定數量的線程數,而不會影響對外的響應時間TP99的承諾。這樣可以提高系統的併發能力。雖然系統可以在高負載下運行,但我們需要進一步進行穩定性測試,以提高系統的可靠性。
綜上所述,線程池大小的合理配置需要結合業務需求和系統資源情況進行評估和測試,並預留合理的buffer空間,以保證系統穩定運行和滿足用户的SLA。
5.附錄
附錄一:統計指標及術語説明
併發用户數:同時發起請求的用户數。
TP值(50/90/99/999):客户端的TP值,單位ms,數據來源於Forcebot。
吞吐量TPS:數據來源於Forcebot。
CPU利用率(%):數據來源於PFinder。
JSF業務線程數:JSF業務線程池的線程數,如:<jsf:server id="jsf" protocol="jsf" threadpool="fixed" _threads_="16" />
fixed/cached:JSF業務線程池的線程池類型,如:<jsf:server id="jsf" protocol="jsf" threadpool="fixed" threads="200"/>
作者:京東物流 劉江波
來源:京東雲開發者社區 自猿其説Tech 轉載請註明來源