平常的工作中,在衡量伺服器的性能時,經常會涉及到幾個名額,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高導緻的?
應用中線程的數量怎麼設定,是越多越好,線程在應用性能中的作用是什麼?
系統負載和應用負荷的關系,系統負載高是由應用負荷引起的,如果不是還有什麼原因?
在進行理論總結之前,對接下來要用到的一些參數做下說明:
注:以下的讨論均限于機器負載小于平均負載的情況,機器負載太高的時候,以下的公式并不适用。
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是一個理論計算值。
現在讓我們用例子在測試驗證下。
注:這裡的使用到的測試用例和資料來源于《伺服器端性能優化-提升QPS、RT - 小邪》
壓測模型如下:
對于我們大多數系統來說,業務邏輯都不是很複雜,需要耗費大量cpu計算的場景很少,是以
Tic在rt中的占比不是很高,占比高的還是Tiw。
壓測結果如下:
結論:
要提高qps,最好的方法是降低Tic,優化cpu時間能達到更好的效果,比如:減少加密、解密、渲染、排序、查找、序列化等操作。
要降低rt,則是降低Tiw,比如依賴的遠端服務、資料庫的讀寫、鎖等,并且降低Tiw并不能帶來qps的明顯提升。
在之前的測試中,有一個既定條件,即線程的大小被預設為最佳線程數,但是線上機器運作過程中,最佳線程數是很難計算的,處理邏輯的線程池大小也不可能剛剛好就是最佳線程數,往往不是大了就是小了,隻能接近于最佳線程數。
線程數過小的結果,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則會變大。
一圖來總結下線程數、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等,是以記憶體也應該被重視,限于篇幅,記憶體的問題不專門展開。
影響系統性能的因素有很多,沒有一個明确的公式或者方法能說明是哪一個具體的因素對系統造成了多大的影響,對其他相關因素又産生了多大的影響,影響是好是壞。
正是因為這種複雜性和不确定性給系統性能優化和查找性能問題帶來了困難,實際工作中還是要針對具體問題具體對待,但是我們可以對已知的問題和方法做歸納和總結,并逐漸在實際問題中去驗證和豐富擴充,以形成解決問題的方法論。