關於伺服器效能的一些思考
一、伺服器效能
平常的工作中,在衡量伺服器的效能時,經常會涉及到幾個指標,load、cpu、mem、qps、rt,其中load、cpu、mem來衡量機器效能,qps、rt來衡量應用效能。
一般情況下對於機器效能,load、cpu、mem是越低越好,如果有一個超過了既定指標都代表著可能出現了問題,就需要儘快解決(當然有可能是應用的問題也有可能是機器上其他程式引起的),反正就是如果不解決,時間長了肯定不好。
而對於應用效能的兩個指標,qps當然是希望越大越好,rt越小越好。提高qps可以充分利用機器資源,更少的機器來完成更多的請求,而降低rt會提升響應速度,提升使用者體驗。
平時做效能優化或者查詢效能問題的目的,就是在提高qps,降低rt、保證load、cpu、mem穩定,但是至於他們之間有什麼關係,是否有相互影響,各個指標主要由那些因素決定等等,往往是兩眼一抹黑。優化點做了就是做了,至於會有什麼結果,為什麼會生效,會不會對其他指標有什麼影響,心裡多少是沒有底的,先上線看看再說,不行再來。
本文的目的是梳理下日常工作中涉及到效能點時的一些思考,總結方法和理論,形成自己的方法論,希望對以後類似的工作有一定的指導。
文章的內容主要來自《伺服器端效能優化-提升QPS、RT》、《由RT、QPS到問題排查思路》兩篇PPT和ata上的一些文案的總結,涉及到具體測試案例可以參考著兩篇ppt中的例子。
在文章開始前,大家可以思考幾個具體的問題:
- 如果要提高qps應該怎麼做,如果要降低rt應該怎麼做?
- qps和rt的關係,降低rt就可以提高qps?qps低是因為rt高導致的?
- 應用中執行緒的數量怎麼設定,是越多越好,執行緒在應用效能中的作用是什麼?
- 系統負載和應用負荷的關係,系統負載高是由應用負荷引起的,如果不是還有什麼原因?
二、應用效能
1、理論討論
在進行理論總結之前,對接下來要用到的一些引數做下說明:
qps:一秒鐘內完成的請求數量
rt: 一個請求完成的時間
Tic: 執行緒的cpu計算時間
Tiw:執行緒的等待時間(io/網路/鎖)
Tn: 執行緒數
Tno:最佳執行緒數
Cn:cpu核數
Cu:cpu使用率
注:以下的討論均限於機器負載小於平均負載的情況,機器負載太高的時候,以下的公式並不適用。
rt的計算公式:
qps計算:
對於rt和qps的計算公式大家都已經很熟悉,不做過多說明,在這裡引出一個重要的概念,最佳執行緒數。
最佳執行緒數的定義:剛好消耗完伺服器瓶頸資源的臨界執行緒數。計算公式如下:
如何理解最佳執行緒數和其計算公式?
在一般的伺服器上,程式執行的瓶頸資源有可能是cpu、也可以是記憶體、鎖、IO等,他們都可以影響到程式執行的時間,體現在公式上就是Tic和Tiw,分表代表程式執行的cpu執行時間和程式等待資源的時間。因此理論上,為了讓cpu充分使用,執行程式的執行緒數就是(Tic + Tiw)/Tic。
這裡說下我對Tic和Tiw的理解,既然瓶頸資源不僅僅只是有cpu,為什麼要把cpu單獨拎出來,而其他種種都歸結為Tiw。我想是因為機器的效能受影響的因素很多,不可能全部體現在公式中,為了方便計算和推理,所以選擇了好統計的Tic做為一個主要指標,而其他都歸結為Tiw。所以這只是一個計算上的技巧,公式不代表真實情況,但是公式可以給我們指明方向,簡化思考的方法。
目前線上機器都是多核的,那麼在多核情況下,應用qps的計算應該是:
Cu是cpu使用率,線上機器一般不會把cpu跑到100%,所以在計算qps時需要乘上一個係數,代表期望cpu使用率使用情況下的qps。
一般寫程式碼的時候還會用到多執行緒,那麼多核多執行緒下qps為:
多核最佳執行緒下qps:
可以看到在最佳執行緒下,qps的大小隻和Tc成反比,也就是說要增大qps只要減小Tic就可以了。
但是最佳執行緒數的計算公式中可以看出,應用的最佳執行緒數是和實際的執行情況相關的,是一個隨時變化的量,在應用執行過程中很難確定一個明確的值,所以qps的計算公式還需要根據實際情況來做下改變。最終qps計算如下,Tn一般是一個確定的值,即處理邏輯執行緒池的大小,而Tno是一個理論計算值。
2、測試驗證
現在讓我們用例子在測試驗證下。
注:這裡的使用到的測試用例和資料來源於《伺服器端效能優化-提升QPS、RT – 小邪》
壓測模型如下:
對於我們大多數系統來說,業務邏輯都不是很複雜,需要耗費大量cpu計算的場景很少,因此
Tic在rt中的佔比不是很高,佔比高的還是Tiw。
壓測結果如下:
結論:
- 要提高qps,最好的方法是降低Tic,優化cpu時間能達到更好的效果,比如:減少加密、解密、渲染、排序、查詢、序列化等操作。
- 要降低rt,則是降低Tiw,比如依賴的遠端服務、資料庫的讀寫、鎖等,並且降低Tiw並不能帶來qps的明顯提升。
3、執行緒的大小
在之前的測試中,有一個既定條件,即執行緒的大小被預設為最佳執行緒數,但是線上機器執行過程中,最佳執行緒數是很難計算的,處理邏輯的執行緒池大小也不可能剛剛好就是最佳執行緒數,往往不是大了就是小了,只能接近於最佳執行緒數。
執行緒數過小的結果,qps上不去,cpu利用率不高,rt不變,這個很好理解,極端情況下只有一個執行緒,那麼Tiw這段時間內,cpu其實是白白浪費了。
執行緒數過大(超過最佳執行緒數),我們先把結論擺出來,再來求證。
之前寫到rt的計算方法是,rt=Tic+Tiw,但是這是單執行緒或者最佳執行緒情況下的,非最佳執行緒情況下,rt的計算公式應該如下:
即:rt = (併發執行緒數/最佳執行緒數)* 最佳執行緒時的rt。
我們對上面的公式進行下處理,可以得到:
為什麼呢,因為實際執行過程中,實際的最佳執行緒數的大小是不會超過設定的執行緒大小的,所以在Tn
當執行緒的數量超過最佳執行緒數之後,rt的則和執行緒數正相關,即執行緒越多rt越長,這其實也是很好理解的,執行緒的rt由Tic和Tiw構成,一般情況下Tic不會有太大的變化,rt變成說明執行緒等待的時間變長,超過最佳執行緒之後,說明執行緒增加了一部分等待時間,有可能是在等待鎖(鎖的競爭更激烈)、或者是在等待cpu排程、或者是執行緒切換太高。
知道了執行緒數量對rt的影響,再回過頭來看看執行緒數量對qps的影響。
線上程數沒有達到最佳執行緒數之前,增加執行緒可以提高qps,同時rt不變(增加不大);當執行緒數超過了最近執行緒則qps不會在提高,而rt則會變大。
4、總結
一圖來總結下執行緒數、qps、rt之間的關係:
在平時的應用效能優化過程中:
- 首先要明確系統的瓶頸在哪裡,是想提高qps還是降低rt,因為二者的思路是完全不同的。
- 其次要逐步摸清應用效能的臨界點,即最佳執行緒數,因為在達到最佳執行緒數之後,系統的表現會和之前完全不同,在超過最佳執行緒數之後,單靠提高執行緒數已經無法提升系統效能。
三、機器效能
接下來讓我們來看看衡量機器效能的指標——load 和 cpu使用率。
cpu使用率:程式在執行期間實時使用的cpu比率。
load:代表著一段時間內正在使用和等待使用cpu的任務平均數,這是一個很玄妙的定義,我至今沒有完全明白它的確切的定義和計算公式。
鑑於load的計算沒有明確的計算公式,因此不好分析影響load的因素,也不好像應用效能那樣總結出影響qps和rt的具體原因,現在只對load表現出來的問題做一些總結。
機器負荷高,但應用負荷不高
即機器的load很高,但是應用的qps、rt都不高,這種情況可能有以下幾種原因:
- 其他資源導致cpu利用率上不去,大量執行緒在執行其他動作或者在等待,比如io的速度太慢,記憶體gc等。
- 如果系統資源不是瓶頸,則由可能是鎖競爭、後端依賴的服務吞吐低、沒有充分利用多核資源,多核卻使用單執行緒。
檢視機器load高的常見方法:
- 機器的io(磁碟io、網路io):vmstat、iostat、sar -b等。
- 網路io:iftop、iptraf、ntop、tcpdump等。
- 記憶體:gc、swap、sar -r。
- 鎖競爭、上下文切換、後端依賴。
機器負荷高,應用負荷也高
即機器load很高,應用qps也很高:
- 典型的cpu型應用,rt中Tiw很小,基本上全是cpu計算,可以嘗試查詢cpu耗的較多的執行緒,降低cpu計算的複雜度。
- 應用的負荷真的很大,當所有優化手段都做了,還是無法降下來,可以考慮加機器,不丟人。
對於load偏高的原因,不僅僅只是有應用自身引起的,機器上其他程式也有可能導致機器整體的load偏高。
四、總結
影響系統效能的具體因素還有很多,如記憶體就是很常見的問題,記憶體洩露、頻繁gc等,因此記憶體也應該被重視,限於篇幅,記憶體的問題不專門展開。
影響系統效能的因素有很多,沒有一個明確的公式或者方法能說明是哪一個具體的因素對系統造成了多大的影響,對其他相關因素又產生了多大的影響,影響是好是壞。
正是因為這種複雜性和不確定性給系統效能優化和查詢效能問題帶來了困難,實際工作中還是要針對具體問題具體對待,但是我們可以對已知的問題和方法做歸納和總結,並逐步在實際問題中去驗證和豐富擴充,以形成解決問題的方法論。
相關文章
- 關於CodeReview的一些思考View
- 關於 Masonry 的一些思考(下)
- 關於 教育孩子的 一些思考
- 關於程式碼的一些思考
- 關於研發效能提升的思考
- 關於目標的一些思考
- 關於賬號安全的一些思考
- 關於微服務劃分的一些思考微服務
- 關於Code Review的一些思考總結View
- 關於RxJava在業務上的一些思考RxJava
- 關於近源滲透的一些思考
- 關於效率、程式與生活的一些思考
- 【原】關於AdaBoost的一些再思考
- 關於設計評審的一些思考
- Chris Dixon:關於移動的一些思考
- 關於REACT正規化的一些思考React
- 關於多層架構一些思考架構
- 關於模擬經營遊戲的一些思考遊戲
- 關於React中動畫不生效的一些思考React動畫
- 關於研發規範化的一些思考
- 近期關於快取設計的一些思考快取
- 關於效率的一些思考:節點創新
- 關於 `storage:link` Artisan 命令的一些思考
- 關於不完全恢復的一些思考
- 關於許可權系統的一些思考
- 關於redis快取資料庫的一些思考Redis快取資料庫
- 關於DDD和COLA的一些總結和思考
- 關於aspnetcore中介軟體的一些思考NetCore
- 關於效能優化的一些實踐優化
- 關於2021年的一些收穫和思考
- 關於技術人員自身能力提升的一些思考
- 關於Java健壯性的一些思考與實踐!Java
- iOS關於換膚和夜間模式的一些思考iOS模式
- 關於研發核心團隊建設的一些思考
- 關於軟體開發的一些常識和思考
- 對於人生的一些思考
- 關於面試的思考面試
- 關於Ioc的思考