您好,登錄后才能下訂單哦!
標簽: 性能 壓測 后端服務(wù) 壓測實踐
作者:王清培(Plen wang)
最近大半年內(nèi)有過兩次負責性能壓測的一些工作。一件事情做了一次可能還無法總結(jié)出一些東西,兩次過后還是能發(fā)現(xiàn)一些共性問題,所以總結(jié)下性能壓測的一般性實踐。但是問題肯定不止這些,還有更多深層次的問題等著發(fā)現(xiàn),等我們遇到了在逐個解決再來總結(jié)分享。
做性能壓測的原因就不多說了,一般兩個時間點是必須要做的,大促前、新系統(tǒng)上線。壓測都是為了系統(tǒng)在線上的處理能力和穩(wěn)定性維持在一個標準范圍內(nèi),做到心中有數(shù)。
從整個行業(yè)來看,拋開一些大廠不說,全自動化的性能壓測環(huán)境還是比較少的,要想建設(shè)好一套全自動化的性能壓測環(huán)境起碼涉及到幾個問題,CI\CD、獨立、隔離的壓測環(huán)境,自動化壓測工具、日常壓測性能報警、性能報表分析、排查/解決性能問題流程等等。這樣才能將性能壓測常規(guī)化,一旦不是常規(guī)化性能壓測,就會有代碼、中間件配置滯后于生產(chǎn)環(huán)境的問題。時間一長,就等于要重新開始搭建、排查壓測環(huán)境。
如果性能壓測的環(huán)境是全自動化的,那么就可以把性能壓測工作常規(guī)化變成研發(fā)過程中的一個例行的事項,執(zhí)行起來效率就會非常高,壓測的時候也會比較輕松,好處也是比較明顯的。
但是大多數(shù)的時候我們還是需要從零開始進行性能壓測的工作。畢竟搭建這樣一套環(huán)境給企業(yè)帶來的成本也是巨大的。性能壓測對環(huán)境敏感,必須劃分獨立的部署、隔離單元,才能在后續(xù)的常規(guī)壓測流程中直觀的閱讀壓測報告。
題外話,如果有了自動化的壓測環(huán)境,也還是需要去了解下整個壓測環(huán)境的基本架構(gòu),畢竟壓測環(huán)境不是真實的生產(chǎn)環(huán)境,有些問題我們需要知道是正常的還是不正常的。
當我們需要進行性能壓測時首先要面對的問題就是環(huán)境問題,環(huán)境問題包含了常見的幾個點:
1.機器問題(實體機還是虛擬機、CPU、內(nèi)存、網(wǎng)絡(luò)適配器進出口帶寬、硬盤大小,硬盤是否 SSD、內(nèi)核基本參數(shù)配置)
2.網(wǎng)絡(luò)問題(是否有跨網(wǎng)段問題、網(wǎng)段是否隔離、如果有跨網(wǎng)段機器,是否能訪問、跨網(wǎng)段是否有帶寬限速)
3.中間件問題(程序里所有依賴的中間件是否有部署,中間件的配置是否初始化、中間件 cluster 結(jié)構(gòu)什么樣、這些中間件是否都進行過性能壓測、壓測的緯度是什么,是 benchmark 還是針對特定業(yè)務(wù)場景的壓測)
這些環(huán)境問題第一次排查的時候會有點累,但是掌握了一些方法、工具、流程之后剩下的也就是例行的事情,只不過人工參與的工作多點。
上面的問題里,有些問題查看是比較簡單的,這里就不介紹了,比如機器的基本配置等。有些配置只需要你推動下,走下相關(guān)流程回頭驗收下,比如網(wǎng)段隔離等,也還是比較簡單的。
比較說不清楚的是中間件問題,看上去都是能用的,但是就是壓不上去,這時候就需要你自己去進行簡單的壓測,比如 db 的單表插入、cache 的并發(fā)讀取、mq 的落地寫入等。這時候就涉及到一個問題,你需要對這些中間件都有一定深度的了解,要知道內(nèi)在的運行機制,要不然出現(xiàn)異常情況排查起來確實很困難。
其實沒有人能熟悉市面上所有的中間件,每一個中間件都很復(fù)雜,我們也不可能掌握一個中間件的所有點,但是常用的一些我們是需要掌握的,至少知道個大概的內(nèi)部結(jié)構(gòu),可以順藤摸瓜的排查問題。
但是事實上總有你不熟悉的,這個時候求助下大家的力量互相探討再自己摸索找點資料,我們沒遇到過也許別人遇到過,學(xué)技術(shù)其實就是這么個過程。
既然做性能壓測就需要先對壓測機、壓力工具先進行了解,壓測工具我們主要有 locust、jmeter、ab,前兩者主要是壓測同事進行準出驗收測試使用的。
后兩者主要是用來提交壓測前的自檢使用,就是開發(fā)自己用來檢查和排錯使用的。這里需要強調(diào)下 ab 其實是做基準測試的,不同于 jmeter 的作用。
需要知道壓力機是否和被壓測機器服務(wù)器在一個網(wǎng)段,且網(wǎng)段之間沒有任何帶寬限制。壓力機的壓測工具配置是否有瓶頸,一般如果是 jmeter 的話需要檢查 java 的一些基本配置。
但是一般如果壓力機是固定不變的,一直在使用的,那么基本不會有什么問題,因為壓力機壓測同事一直維護者,反而是自己使用的壓測工具的參數(shù)要做好配置和檢測。
用 jmeter 壓測的時候,如果壓測時間過長,記得關(guān)掉 監(jiān)聽器->圖形結(jié)果 面板,因為那個渲染如果時間太長基本會假死,誤以為會是內(nèi)存的問題,其實是渲染問題。
在開發(fā)做基準壓測的時候有一個問題就是辦公網(wǎng)絡(luò)與壓測服務(wù)器的網(wǎng)絡(luò)之間的帶寬問題,壓力過大會導(dǎo)致辦公網(wǎng)絡(luò)出現(xiàn)問題。所以需要錯開時間段。
大致梳理好后,我們需要通過一些工具來查看下基本配置是否正常。比如,ethtool 網(wǎng)絡(luò)適配器信息、nload 流量情況等等,當然還有很多其他優(yōu)秀的工具用來查看各項配置,這里就不羅列了。
使用 ethtool 查看網(wǎng)絡(luò)適配器信息前需要先確定當前機器有幾個網(wǎng)絡(luò)適配器,最好的辦法是使用 ifconfig 找到你正在使用的網(wǎng)絡(luò)適配器。
排除 127.0.0.1 的適配器外,還有三個適配器信息,只有第一個 bond0 才是我們正在使用的,然后使用 ethtool 查看當前 bond0 的詳細適配器信息。重點關(guān)注下 speed 域,它表示當前網(wǎng)絡(luò)適配器的帶寬。
雖然網(wǎng)絡(luò)適配器可能配置的沒有問題,但是整個網(wǎng)絡(luò)是否沒問題還需要咨詢相關(guān)的運維同事進行排查下,中間還可能存在限速問題。
要確定網(wǎng)絡(luò)帶寬確實沒有問題,我們還需要一個實時的監(jiān)控網(wǎng)絡(luò)流量工具,這里我們使用nload來監(jiān)控下進出口流量問題。
這個工具還是很不錯的,尤其是在壓測的過程中可以觀察流量的進出口情況,尤其是排查一些間隙抖動情況。
如果發(fā)現(xiàn)進口流量一直很正常,出口流量下來了有可能系統(tǒng)對外調(diào)用再放慢,有可能是下游調(diào)用 block,但是 request 線程池還未跑滿,也有可能內(nèi)部是純 async ,request 線程根本不會跑滿,也有可能是壓測工具本身的壓力問題等等。但是我們至少知道是自己的系統(tǒng)對外調(diào)用這個邊界出了問題。
工作環(huán)境中,一般情況下 linux 打開文件句柄數(shù)上限是不需要我們設(shè)置的,這些初始化的值運維同事一般是設(shè)置過的,而且是符合運維統(tǒng)一標準的。但是有時候關(guān)于最大連接數(shù)設(shè)置還要根據(jù)后端系統(tǒng)的使用場景來決定。
以防萬一我們還是需要自己檢查下是否符合當前系統(tǒng)的壓測要求。
在 Linux 中一切都是文件,socket 也是文件,所以需要查看下當前機器對于文件句柄打開的限制,查看 ulimit -a 的 open files 域,也可以直接查看ulimit -n 。
如果覺得配置的參數(shù)需要調(diào)整,可以通過編輯 /etc/security/limits.conf 配置文件。
要想對一個服務(wù)進行壓測,就需要對這個服務(wù)周邊依賴進行一個排查,有可能你所依賴的服務(wù)不一定具備壓測條件。并不是每個系統(tǒng)的壓測都在一個時間段內(nèi),所以你在壓測的時候別人的服務(wù)也許并不需要壓測等等。
還有類似中間件的問題,比如,如果我們依賴中間件 cache ,那么是否有本地一級 cache ,如果有的話也許對壓測環(huán)境的中間件 cache 依賴不是太大。如果我們依賴中間件 mq ,是不是在業(yè)務(wù)上可以斷開對 mq 的依賴,因為我們畢竟不是對 mq 進行壓測。還有我們所依賴服務(wù)也不關(guān)心我們的壓測波動。
整理出來之后最好能畫個草圖,再重新 git branch -b 重新拉一個性能壓測的 branch 出來根據(jù)草圖進行調(diào)整代碼依賴。然后壓測的時候觀察流量和數(shù)據(jù)的走向,是否符合我們梳理之后的路線。
為了快速驗證壓測服務(wù)一個簡單的辦法,就是通過壓測一個空接口,查看下整個網(wǎng)絡(luò)是否通暢,各個參數(shù)是否大體上正常。
一般在任何一個后端服務(wù)中,都有類似 __health_check 的 endpoint,方便起見可以直接找一個沒有任何下游依賴的接口進行壓測,這類接口主要是為了驗證服務(wù)器的 online、offline__ 狀態(tài)。
如果當前服務(wù)沒有類似 __health_check__ 新建一個空接口也可以,而且實踐證明,一個服務(wù)在生產(chǎn)環(huán)境非常需要這么一個接口,必要情況下可以幫助來排查調(diào)用鏈路問題。
《發(fā)布!軟件的設(shè)計與部署》Jolt 大獎圖書 第17章 透明性 介紹了架構(gòu)的透明性設(shè)計作用。
我們在用 jmeter 進行壓測的時候關(guān)于 聚合報告 中的 throughput 理解需要統(tǒng)一下。
正常情況下在使用 jmeter 壓測的時候會仔細觀察 throughput 這一列的變化情況,但是沒有搞清楚 thourghput 的計算原理的時候就會誤以為是 tps/qps 下來了,其實有時候是整個遠程服務(wù)器根本就沒有 response 了。
throughput=samples/壓測時間
throughput(吞吐量) 是單位時間內(nèi)的請求處理數(shù),一般是按 second 計算,如果是壓測 write 類型的接口,那么就是 tps 指標。如果壓測 read 類型的接口,那么就是 qps 指標。這兩種類型的指標是完全不一樣的,我們不能搞混淆了。
200(throughput) tps=1000(write)/5(s)
1000(throughput) qps=2000(read)/2(s)
當我們發(fā)現(xiàn) throughput 逐漸下來的時候要考慮一個時間的緯度。
也就是說我們的服務(wù)有可能已經(jīng)不響應(yīng)了,但是隨著壓測時間的積累,整個吞吐量的計算自然就在緩慢下滑,像這種刺尖問題是發(fā)現(xiàn)不了的。
這一點用ui版本的 jmeter 尤其明顯,因為它的表現(xiàn)方式就是在歡歡放慢。用 Linux 版本的 jmeter 還好點,因為它的輸出打印是隔斷時間才打印。
關(guān)于這個點沒有搞清楚非常影響我們對性能壓測的結(jié)果判斷。所以我們在壓測的時候一定要有監(jiān)控報表,才能知道在整個壓測過程中服務(wù)器的各項指標是否出現(xiàn)過異常情況。
大多數(shù)的時候我們還會使用 apache ab 做下基本的壓測,主要是用來與 jmeter 對比下,兩個工具壓測的結(jié)果是否相差不大,主要用來糾偏一些性能虛高問題。
apache ab 與 jmeter 各有側(cè)重,ab 可以按固定請求數(shù)來壓,jmeter 可以按時間來壓,最后計算的時候需要注意兩者區(qū)別。ab 好像是沒有請求錯誤提示和中斷的,jmeter 是有錯誤提示,還有各個緯度斷言設(shè)置。
我們在使用壓測工具的時候,大致了解下工具的一些原理有助于準確的使用這款工具。
在文章的前面部分講到了 排查周邊依賴 的環(huán)境檢查步驟。其實要想順利的進行壓測,這一步是必須要有的。經(jīng)過這一步分析我們會有一個基本的 系統(tǒng)依賴 roadmap 。
基于這份 系統(tǒng)依賴 roadmap 我們將進行性能壓測和問題定位及性能優(yōu)化。
合理的系統(tǒng)架構(gòu)應(yīng)該是上層依賴下層,在沒有確定下游系統(tǒng)性能的情況下,是沒辦法確定上游系統(tǒng)性能的瓶頸在哪里。
所以壓測的順序應(yīng)該盡可能的從下往上依次進行,這樣可以避免無意義的排查由于下游吞吐量不夠帶來的性能問題。越是下游系統(tǒng)性能要求越高,因為上游系統(tǒng)的性能瓶頸直接依賴下游系統(tǒng)。
比如,商品系統(tǒng)的 v1/product/{productid} 前臺接口,吞吐量為 qps 8000,那么所有依賴這個接口的上游服務(wù)在這個代碼路徑上最高吞吐量瓶頸就是 8000 ,代碼路徑不管是 tps 還是 qps 都是一樣的瓶頸。
上層服務(wù)可以使用 async方式來提高 request 并發(fā)量,但是無法提高代碼路徑在 v1/product/{productid} 業(yè)務(wù)上的吞吐量。
我們不能將并發(fā)和吞吐量搞混淆了,系統(tǒng)能扛住多少并發(fā)不代表吞吐量就很高??梢杂泻芏喾绞絹硖岣卟l(fā)量,threadpool 提高線程池大小 、socket 類c10k 、nio事件驅(qū)動,諸如此類方法。
當在壓測的過程中定位性能問題的性價比較高的方法就是請求處理的log,請求處理時長log,對外接口調(diào)用時長log,這一般能定位大部分比較明顯的問題。當我們用到了一些中間件的時候都會輸出相應(yīng)的執(zhí)行l(wèi)og。
如下所示,在我們所使用的開發(fā)框架中支持了很多緯度的執(zhí)行l(wèi)og,這在排查問題的時候就會非常方便。
slow.log 類型的慢日志還是非常有必要記錄下來的,這不僅在壓測的時候需要,在生產(chǎn)上我們也是非常需要。
如果我們使用了各種中間件,那就需要輸出各種中間件的處理日志,mq.log、cache.log、search.log 諸如此類。
除了這些 log 之外,我們還需要重點關(guān)注運行時的 gc log。
我們主要使用 Java 平臺,在壓測的時候關(guān)注 gc log 是正常的事。哪怕不是 Java 程序,類似基于 vm 的語言都需要關(guān)注 gc log 。根據(jù) jvm gcer 配置的不同,輸出的日志也不太一樣。
一般電商類的業(yè)務(wù),以響應(yīng)為優(yōu)先時 gc 主要是使用 cms+prenew ,關(guān)注 full gc 頻次,關(guān)注 cms 初始標記、并發(fā)標記、重新標記、并發(fā)清除 各個階段執(zhí)行時間, gc 執(zhí)行的 real time ,pernew 執(zhí)行時的內(nèi)存回收大小等 。
java gc 比較復(fù)雜涉及到的東西也非常多,對 gc log 的解讀也需要配合當前的內(nèi)存各個代的大小及一系列 gc 的相關(guān)配置不同而不同。
《Java性能優(yōu)化權(quán)威指南》 java之父gosling推薦,可以長期研究和學(xué)習。
在壓測的過程中為了能觀察到系統(tǒng)的各項資源消耗情況我們需要借助各種工具來查看,主要包括網(wǎng)絡(luò)、內(nèi)存、處理器、流量。
###netstat
主要是用來查看各種網(wǎng)絡(luò)相關(guān)信息。
比如,在壓測的過程中,通過 netstat wc 看下 tcp 連接數(shù)是否和服務(wù)器 threadpool 設(shè)置的匹配。
netstat -tnlp | grep ip | wc -l
如果我們服務(wù)器的 threadpool 設(shè)置的是50,那么可以看到 tcp 連接數(shù)應(yīng)該是50才對。然后再通過統(tǒng)計 jstack 服務(wù)器的 request runing 狀態(tài)的線程數(shù)是不是>=50。
request 線程數(shù)的描述信息可能根據(jù)使用的 nio 框架的不同而不同。
還有使用頻率最高的查看系統(tǒng)啟動的端口狀態(tài)、tcp 連接狀態(tài)是 establelished 還是 listen 狀態(tài)。
netstat -tnlp
再配合 ps 命令查看系統(tǒng)啟動的狀態(tài)。這一般用來確定程序是否真的啟動了,如果啟動了是不是 listen 的端口與配置中指定的端口不一致。
ps aux | grep ecm-placeorder
netstat 命令很強大有很多功能,如果我們需要查看命令的其他功能,可以使用man netstat 翻看幫助文檔。
主要用來監(jiān)控虛擬處理器的運行隊列統(tǒng)計信息。
vmstat 1
在壓測的時候可以每隔 1s 或 2s 打印一次,可以查看處理器負載是不是過高。procs 列 r 子列就是當前處理器的處理隊列,如果這個值超高當前 cpu core 數(shù)那么處理器負載將過高??梢院拖旅鎸⒔榻B的 top 命令搭配著監(jiān)控。
同時此命令可以在處理器過高的時候,查看內(nèi)存是否夠用是否出現(xiàn)大量的內(nèi)存交換,換入換出的量多少 swap si 換入 swap so 換出。是否有非常高的上下文切換 system cs 每秒切換的次數(shù),system us 用戶態(tài)運行時間是否很少。是否有非常高的 io wait 等等。
關(guān)于這個命令網(wǎng)上已經(jīng)有很多優(yōu)秀的文章講解,這里就不浪費時間重復(fù)了。同樣可以使用 man vmstat 命令查看各種用法。
主要用來監(jiān)控多處理器統(tǒng)計信息
mpstat -P ALL 1
我這是一個 32 core 的壓測服務(wù)器,通過 mpstat 可以監(jiān)控每一個虛擬處理器的負載情況。也可以查看總的處理器負載情況。
mpstat 1
可以看到 %idle 處于閑置狀態(tài)的 cpu 百分比,%user 用戶態(tài)任務(wù)占用的 cpu 百分比,%sys 系統(tǒng)態(tài)內(nèi)核占用 cpu 百分比,%soft 軟中斷占用 cpu 百分比,%nice 調(diào)整任務(wù)優(yōu)先級占用的 cpu 百分比等等。
主要用于監(jiān)控io統(tǒng)計信息
iostat 1
如果我們有大量的 io 操作的話通過 iostat 監(jiān)控 io 的寫入和讀取的數(shù)據(jù)量,同時也能看到在 io 負載特別大的情況下 cpu 的平均負載情況。
監(jiān)控整個系統(tǒng)的整體性能情況
top 命令是我們在日常情況下使用頻率最高的,可以對當前系統(tǒng)環(huán)境了如指掌。處理器 load 率情況,memory 消耗情況,哪個 task 消耗 cpu 、memory 最高。
top
top 命令功能非常豐富,可以分別根據(jù) %MEM、%CPU 排序。
load average 域表示 cpu load 率情況,后面三段分別表示最近1分鐘、5分鐘、15分鐘的平均 load 率。這個值不能大于當前 cpu core 數(shù),如果大于說明 cpu load 已經(jīng)嚴重過高。就要去查看是不是線程數(shù)設(shè)置的過高,還要考慮這些任務(wù)是不是處理時間太長。設(shè)置的線程數(shù)與任務(wù)所處理的時長有直接關(guān)系。
Tasks 域表示任務(wù)數(shù)情況,total 總的任務(wù)數(shù),running 運行中的任務(wù)數(shù),sleeping 休眠中的任務(wù)數(shù),stopped 暫停中的任務(wù)數(shù),zombie 僵尸狀態(tài)任務(wù)數(shù)。
Swap 域表示系統(tǒng)的交換區(qū),壓測的時候關(guān)注 used 是否會持續(xù)升高,如果持續(xù)升高說明物理內(nèi)存已經(jīng)用完開始進行內(nèi)存頁的交換。
查看當前系統(tǒng)的內(nèi)存使用情況
free -m
total 總內(nèi)存大小,used 已經(jīng)分配的內(nèi)存大小,free 當前可用的內(nèi)存大小,shared 任務(wù)之間的共享內(nèi)存大小,buffers 系統(tǒng)已經(jīng)分配但是還未使用的,用來存放文件 matedata 元數(shù)據(jù)內(nèi)存大小,cached 系統(tǒng)已經(jīng)分配但是還未使用的,用來存放文件的內(nèi)容數(shù)據(jù)的內(nèi)存大小。
-/+buffer/cache
used 要減去 buffers/cached ,也就是說并沒有用掉這么多內(nèi)存,而是有一部分內(nèi)存用在了 buffers/cached 里。
free 要加上 buffers/cached ,也就是說還有 buffers/cached 空余內(nèi)存需要加上。
Swap 交換區(qū)統(tǒng)計,total 交換區(qū)總大小,used 已經(jīng)使用的交換區(qū)大小,free 交換區(qū)可用大小。只需要關(guān)注 used 已經(jīng)使用的交換區(qū)大小,如果這里有占用說明內(nèi)存已經(jīng)到瓶頸。
《深入理解LINUX內(nèi)核》、《LINUX內(nèi)核設(shè)計與實現(xiàn)》可以放在手邊作為參考手冊遇到問題翻翻。
當系統(tǒng)出現(xiàn)性能問題的時候可以從兩個層面來排查問題,從上往下、從下網(wǎng)上,也可以綜合運用這兩種方法,壓測的時候可以同時查看這兩個緯度的信息。
一邊打開 top 、free 觀察 cpu 、memory 的系統(tǒng)級別的消耗情況,同時一邊在通過 jstack 、jstat 之類的工具查看應(yīng)用程序運行時的內(nèi)部狀態(tài)來綜合定位。
本篇文章主要還是從拋磚引玉的角度出發(fā),整理下我們在做一般性能壓測的時候出現(xiàn)的常規(guī)問題及排查方法和處理流程,并沒有多么高深的技術(shù)點。
性能問題一旦出現(xiàn)也不會是個簡單的問題,都需要花費很多精力來排查問題,運用各種工具、命令來逐步排查,而這些工具和命令所輸出的信息都是系統(tǒng)底層原理,需要逐一去理解和實驗的,并沒有一個銀彈能解決所有問題。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。