系統(tǒng)性能定義
1.Throughtput,吞吐量。每秒鐘可以處理的請求數(shù),任務(wù)數(shù)。
2.Latency,系統(tǒng)延遲。系統(tǒng)在處理一個(gè)請求或一個(gè)任務(wù)時(shí)的延遲。

image.png
兩者的關(guān)系:
- throughput越大,Latency越差。因?yàn)檎埱筮^多,系統(tǒng)繁忙,自然響應(yīng)速度會降低。
- latency越好,能支持的Throughput越高。latency短說明系統(tǒng)處理速度快,自然便可以處理更多的請求。
要說明一個(gè)系統(tǒng)的性能,便需要收集系統(tǒng)的Throughput和Latency兩個(gè)值。
- 首先,需要定義Latency這個(gè)值。這個(gè)值的意義不是普適性的,需要根據(jù)不同的業(yè)務(wù)來定義,比如一些實(shí)時(shí)系統(tǒng),需要的latency便會很短,如5ms。
- 其次,開發(fā)性能測試工具。一個(gè)用來制造高強(qiáng)度的Throughput,另一個(gè)用來監(jiān)測latency。對一個(gè)工具可以用很多現(xiàn)有開源的或者商業(yè)的。
latency可以通過在代碼中打日志測量,但是會影響到程序的執(zhí)行,而且也只能看到代碼內(nèi)部的latency,無法計(jì)算到線上系統(tǒng)的。對于網(wǎng)絡(luò)延遲可以使用一些抓包工具。 - 最后,開始性能測試。不斷的調(diào)整throughput,觀察系統(tǒng)負(fù)載,觀察latency。找到系統(tǒng)的最大負(fù)載并且知道系統(tǒng)的響應(yīng)延遲是多少。
定位性能瓶頸
當(dāng)在測試過程中,發(fā)現(xiàn)性能有問題時(shí),不用急于去懷疑代碼。首先要查看操作系統(tǒng)的報(bào)告,查看OS的cpu使用率,內(nèi)存使用率,查看系統(tǒng)IO和網(wǎng)絡(luò)的IO,網(wǎng)絡(luò)連接數(shù)。通過觀察以上數(shù)據(jù),基本可以判斷出性能問題出在哪。
- CPU使用率。如果使用率不高,但是Throughput和latency上不去,說明我們的程序沒有忙于計(jì)算,而是干了別的事情,比如IO。
- 然后可以看下IO大不大,IO和CPU一般反著來,CPU利用率高則IO低,IO大則CPU小。IO看三個(gè)點(diǎn),磁盤文件IO,驅(qū)動(dòng)程序的IO,內(nèi)存換頁率。
- 查看網(wǎng)絡(luò)帶寬狀態(tài)。
- 如果CPU不高,IO不高,內(nèi)存使用不高,網(wǎng)絡(luò)帶寬使用不高,但是系統(tǒng)性能上不去,說明程序可能有問題。比如程序被阻塞,或者是一些數(shù)據(jù)庫的索引未建立。
性能測試結(jié)果的分析:
結(jié)合jmeter的測試報(bào)告

image.png
上圖是一個(gè)jmeter的測試報(bào)告,在報(bào)告中,有平均響應(yīng)時(shí)間和90%,95%,99%的響應(yīng)時(shí)間。
首先給結(jié)論:平均值不靠譜
再來說說為什么,在進(jìn)行性能測試時(shí),得到的結(jié)果數(shù)據(jù)不會都一樣,而是有高有低。例如測試了10次,有9次都是1ms,但是第十次的時(shí)間是2s,那么平均值就是200.9,很明顯這個(gè)并不能正確反映我們系統(tǒng)的性能。這個(gè)2s,應(yīng)該作為一個(gè)異常值去除掉。就好像體育比賽一樣,很多項(xiàng)目評委打分時(shí),是需要去掉一個(gè)最高分和最低分的。
設(shè)備指紋4.x的版本中,js集成在server中,當(dāng)頁面集成了js時(shí),需要先下載js,然后才是使用js拿到設(shè)備指紋。第一次下載后,js便會緩存在本地,方便以后調(diào)用就不需要每次都去下載js了。
而下載js便會受到網(wǎng)絡(luò)的影響。在測試時(shí),經(jīng)常下載js會達(dá)到秒級。所以在性能測試時(shí),需要將下載js的這個(gè)動(dòng)作不納入統(tǒng)計(jì)中。
正確的統(tǒng)計(jì)是使用百分比分布統(tǒng)計(jì)
然后繼續(xù)看上面的圖,99%Line;
這個(gè)就是表示99%的請求均小于某值,在測試過程中,應(yīng)該重點(diǎn)關(guān)注這樣的數(shù)據(jù)結(jié)果。
常見系統(tǒng)瓶頸
代碼調(diào)優(yōu)
- 類型轉(zhuǎn)換。
之前在3.x的設(shè)備指紋中,出現(xiàn)過嚴(yán)重的性能下降問題,后來定位發(fā)現(xiàn),是在類型轉(zhuǎn)換時(shí)用了fastjson的一個(gè)方法,導(dǎo)致系統(tǒng)時(shí)間大量的耗在上面了。 - 異步操作。有些同步操作,會非常影響性能,尤其在網(wǎng)絡(luò)較差的情況下,很可能阻塞我們的業(yè)務(wù)。使用異步,可以提升性能但是會帶來編碼上的復(fù)雜性。異步下的狀態(tài)通知通常是個(gè)問題,比如消息事件通知方式,有回調(diào)方式等,這些方式同樣可能會影響性能。但是通常來說,異步操作會讓性能的吞吐率有很大提升(Throughput),但是會犧牲系統(tǒng)的響應(yīng)時(shí)間(latency)。
現(xiàn)在4.5的設(shè)備指紋中,便將以前的同步日志改成了異步寫日志。 - IO模型調(diào)優(yōu)
之前在學(xué)習(xí)netty的過程中,了解了幾種不同的網(wǎng)絡(luò)IO模型,這個(gè)需要根據(jù)自己的業(yè)務(wù)情況選擇合適的IO模型。
系統(tǒng)調(diào)優(yōu)
- 多核CPU調(diào)優(yōu)。之前在使用mongo的時(shí)候,每次進(jìn)入mongo shell ,總是會打印幾串warning,由于平時(shí)是只看error忽略warning的,就沒太在意。后來線上性能除了問題,才注意看了那幾個(gè)warning。其中一個(gè)就是NUMA。
NUMA技術(shù)(Non-Uniform Memory Access)。
NUMA的相關(guān)策略:
- 每個(gè)進(jìn)程(或線程)都會從父進(jìn)程繼承NUMA策略,并分配有一個(gè)優(yōu)先node。如果NUMA策略允許的話,進(jìn)程可以調(diào)用其他node上的資源。
簡單點(diǎn)說,在有多個(gè)物理CPU的架構(gòu)下,NUMA把內(nèi)存分為本地和遠(yuǎn)程,每個(gè)物理CPU都有屬于自己的本地內(nèi)存,訪問本地內(nèi)存速度快于訪問遠(yuǎn)程內(nèi)存,缺省情況下,每個(gè)物理CPU只能訪問屬于自己的本地內(nèi)存。對于MongoDB這種需要大內(nèi)存的服務(wù)來說就可能造成內(nèi)存不足
網(wǎng)絡(luò)調(diào)優(yōu)
- TCP調(diào)優(yōu)
TCP鏈接一是會占用文件描述符,另一個(gè)是會開緩存,一般來說一個(gè)系統(tǒng)可以支持的TCP鏈接數(shù)是有限的,TCP鏈接對系統(tǒng)的開銷是很大的。正是因?yàn)門CP是耗資源的,所以對于TCP的鏈接數(shù)量需要關(guān)注。當(dāng)過多時(shí),很可能大量消耗資源導(dǎo)致系統(tǒng)無響應(yīng)。之前線上反饋,服務(wù)端的鏈接數(shù)過多,后來排查發(fā)現(xiàn),是因?yàn)榘沧縮dk使用了HTTP1.1,默認(rèn)開啟的是keepalive長連接導(dǎo)致的鏈接不釋放。
所以,我們要注意配置KeepAlive參數(shù),這個(gè)參數(shù)的意思是定義一個(gè)時(shí)間,如果鏈接上沒有數(shù)據(jù)傳輸,系統(tǒng)會在這個(gè)時(shí)間發(fā)一個(gè)包,如果沒有收到回應(yīng),那么TCP就認(rèn)為鏈接斷了,然后就會把鏈接關(guān)閉,這樣可以回收系統(tǒng)資源開銷。(注:HTTP層上也有KeepAlive參數(shù))對于像HTTP這樣的短鏈接,設(shè)置一個(gè)1-2分鐘的keepalive,這可以在一定程度上防止DoS攻擊。
數(shù)據(jù)庫調(diào)優(yōu)
傳統(tǒng)的關(guān)系型數(shù)據(jù)庫不太了解,對于NOSQL數(shù)據(jù)庫,例如mongodb,需要關(guān)注索引的情況。之前在測試設(shè)備指紋的時(shí)候,便出現(xiàn)了系統(tǒng)性能越跑越慢的情況,后來發(fā)現(xiàn)是索引建立不全導(dǎo)致的。