【閑說】性能測試
版權聲明:本文為本作者原創文章,轉載請注明出處。感謝 碼夢為生| 劉錕洋 的投稿
性能測試是一件看起來不簡單,操作起來確更困難的事情,我認為,每認真做一次性能測試,一定會有不同收獲,而每次性能測試暴露的問題,現象都不是僅僅涉及Java,tomcat這麼簡單,簡單說就是光會寫代碼是無法做好性能測試的。
那麼,就趁著這次性能測試的機會,重新梳理下對linux,網絡IO等基本功的認識已經就性能瓶頸的定位分享下自己的心得。
背景:
本次性能測試的目的是測試使用公司內部RPC框架開發的一套接口的性能,目的是準確的拿到接口的性能指標,當然,我也想換個角度去看待代碼,比如,從性能或者對操作係統友好的角度,首先略過1萬字的環境搭建過程,其實,性能測試是件非常考驗細心程度的活,需要你對整個組網環境,調用關係,業務邏輯非常清晰,能正確識別出壓力機,應用服務器,數據庫服務器,緩存服務器各自的職責,並在可能的情況下壓榨其性能極限,以及清楚明白可能對其性能造成影響的命令和操作(比如jvm啟動參數中,大部分日誌打印相關參數,關閉即時編譯,調整GC分帶的大小和比例等等)。
其次,還需要你能清楚本次測試程序的核心流程,業務邏輯,盡可能的將一些非核心的組件可能造成的影響去除掉,比如,本次測試的是RPC接口的性能和業務處理的效率,而相應涉及到的分布式緩存,數據庫,則不是本次測試的重點,因此,組網時,應該盡可能將分布式緩存,數據庫等機器與應用服務器放在同一個局域網網段內甚至同一台機器上,保證不會因為他們的表現而直接影響測試目標測試結果。總之,Mock掉一切非核心,不相關的因素。
測試工具/命令
因為是對RPC接口做測試(而非HTTP接口),使用loadRunner等測試工具無法滿足要求,所以在測試工具的選擇上,使用了jmeter。這是一款100%java實現的性能測試工具,使用方式是,繼承他的AbstractJavaSamplerClient抽象類,在其runTest方法中編寫測試用例即可在Jmeter的客戶端中發現測試jar包,從而配置線程數後開始性能測試。具體使用請google之。
在壓力機上部署好jmeter後,多線程開始執行測試用例,用例開始向應用服務器發送調用請求。這個時候設置的並發數應該盡量讓壓力機的CPU達到一個較高的值,比如 70%左右,jemeter提供了預熱功能,必要時候可以使用預熱功能將壓力慢慢加大。
下麵,我們借這次性能測試的機會介紹幾個很好用的命令,啟動後可以先到應用服務器上使用top命令,觀察其CPU利用率,按數字鍵1,詳細查看每個CPU的利用率。 理想情況,這個時候應該可以看到一定的壓力。
也可以使用 vmstat命令,比如: vmstat 1 30 標示,每隔一秒打印一次統計信息,統計30秒。
通常主要關注r 和b 分別代表運行隊列的數量和阻塞個數。理想情況應該是r比較多,b沒有。
具體vmstat命令的結束可以看:https://www.cnblogs.com/ggjucheng/archive/2012/01/05/2312625.html
關注完CPU,還可以使用iostat命令 查看IO的情況,命令格式類似vmstat, iostat 1 30 表示同樣的意思:每秒打印一次統計信息,打印30次後退出。
這裏使用iostat -dx 1 每隔一秒打印一次磁盤的詳細信息 具體可以參看這裏:https://www.cnblogs.com/peida/archive/2012/12/28/2837345.html
可以看到io並不頻繁。都是在很低 的水平上,因此IO應該不是此次性能測試的瓶頸所在。
看完vmstat,iostat,如果都不是處在很高的水平,下一個應該優先看網絡,是的,對於linux還有一個netstat,使用方式與前兩種不同,但是功能同樣強大,可以列出應用服務器上所有tcp連接的詳細信息。通常情況,可以觀察下應用服務器上的TCP連接數,連接狀態是否正常等來判斷應用是否運行正常。
很好用的工具,動手輸一下,你就會知道它的功能了。
測試目的
一般測試的目的有兩個:
1. 是獲取接口的性能,常用TPS,延遲,QPS等衡量。
2. 是通過性能測試,找出性能瓶頸,定位並優化它。
因此,性能測試必須要滿足的一個原則是,要麼把壓力機跑滿,要麼讓應用服務器的某項指標跑滿,之所以說某項指標,是因為,根據應用的不同,例如:CPU密集型應用,IO密集型應用,相應的,性嫩測試的時候應該盡量讓CPU利用率或者IO利用率達到一個較高的水平。
如果有一項指標沒有達標,那性能瓶頸的定位過程就來了。
瓶頸定位
要定位瓶頸,首先需要知道應用服務器的哪項指標沒有達到預期,是CPU利用率還是IO利用率或是都不高,這可以通過以上介紹的三個stat工具觀察出來,如果沒有看到哪項值比較高,至少也可以得到“都不高”的結論,而都不高的時候,或許意味著你的應用程序不像你想象的那麼高效,一定,一定,在某個點上正在激烈的競爭者或者阻塞。程序會平白無故效率低下!
當然除了通過利用率,可以看到CPU或者IO的忙閑程度,有時我們還需要知道具體的數字,比如,哪種IO才算繁忙?
舉個例子,這次性能測試時我使用了一個工具:ifstat,它並非係統自帶的工具,需要手動安裝,安裝過程非常簡單,自行google即可。
安裝完畢後,將ifsta命令加入到path變量中,即可在全局使用ifstat命令,使用後的效果大致是這樣:
eth0 代表了操作係統的第一張網卡。從這裏可以看到此時這張網卡的讀入速率是15M,出口是8M左右,而這張網卡的速率為:
也就是1000Mbit/s ,因為8B10B編碼的關係,換算後理論的帶寬為100M/S,100:15 利用率為15%,這個時候我們才可以說IO的利用率不高。IO不算繁忙。
同樣的,有時會出現一種情況:CPU,網絡/磁盤IO都不高,同樣TPS也不高,這個時候可以從程序入手,分析下是否是程序執行緩慢的原因,原因大致有這麼幾種:
1. 有代碼在串行的某件事,比如打日誌(這次我就遇到了因為我使用自己寫的工具監控方法執行時間的關係,在性能測試時有大量打印日誌和計算工作 ,導致應用程序TPS非常低,拿掉工具後TPS才恢複到一個正常的水平,當然,這就不是說我的工具就不好用(笑) ,有興趣的可以看下工具的介紹,總的來說還是很好用的,工具地址: https://github.com/liuinsect/Profiler)。
2. 多線程競爭,比如,多線程環境下,鎖的競爭,對象監視器的競爭,數據庫,分布式緩存連接的競爭(如果使用連接池的話)等。
3. 過於冗長,複雜方法的執行,雖然JIT可以執行一定程度上的優化,但是,糟糕代碼無下限,要想寫得爛,總是可以的。
4. 所依賴的係統慢,比如,數據庫,分布式緩存慢(當然,他們的慢有更多種可能,有時候甚至需要找到他們慢的原因,並mock掉)。
這個時候就要借助visual vm等工具了。
因為很多時候我們是想在本地,去連接遠程服務器上的JVM,這就涉及到了遠程連接JVM的問題,可以這麼做:
1.首先必須在遠程機器上麵啟動jstatd這個後台進程。它位於JDK安裝路徑的bin目錄裏麵。配置java安全訪問,在jstatd所在的目錄的下新建文件jstatd.all.policy,在我的機器上是/usr/java/jdk1.7.0_05/bin
1 |
grant codebase “file:${java.home}/../lib/tools.jar” { |
2 |
3 |
permission java.security.AllPermission; |
4 |
5 |
}; |
注意結尾還有一個分號。
2.然後用如下命令啟動jstatd:
jstatd -J-Djava.security.policy=jstatd.all.policy
正常啟動沒有任何輸出。默認打開端口是1099,也可以通過-p 參數設置端口。
3. 在本地打開 visual vm ,輸入遠程服務器的IP後,即可連接了。
當然,因為隻是啟動了jstatd,通過visual是不能使用線程監控,CPU監控的,如果需要用到這些功能的話,還需要使用JMX去遠程連接tomcat 。方法在這裏:https://www.oschina.net/question/162973_105064
通過visual vm 已經可以觀察到GC的情況,運行的線程數,是Block,Running 等等情況了,如果應用程序競爭激烈,應該會看到線程運行條上有一段一段的紅色區域,代表線程正在被頻繁阻塞,再想深入,可用通過visual vm 將線程情況dump下來(當然,也可以在應用服務器上使用jstack -m <pid>),查看線程都被哪些對象阻塞,線程的調用棧是什麼樣子的, 從而定位到,應用程序中哪段代碼有頻繁競爭,為什麼競爭,是否可以優化等。
當然,除了使用visual vm 還可以使用linux上的另外一個工具 perf ,他是linux 自帶的性能分析工具。可以通過它看到係統執行的性能情況,功能實在強大,比如:
1. 列出L1,L2,L3 Cache的命中率(需要硬件支持,這次我們性能測試的機器不支持它)
2. 列出係統/進程的性能統計信息 命令: perf top -p pid
3. 分析程序的整體性能 perf stat
等等, 具體可以參考這裏: https://iamzhongyong.iteye.com/blog/1908118
關於perf,這次還有一個小小的故事,在測試接口的某個方法時,使用perf觀察到JVM的反射相關的方法耗時開銷非常高,這才想起來反射相關的代碼沒有對反射的結果做緩存,因此果斷回去加上緩存後,看到前麵的方法在perf的列表中消失,這才放下心。
總結:
通過以上介紹的性能測試的思路和工具,我們基本上可以完成一次性能測試以及部分問題的性能定位,但是往往性能問題總是隱藏得很深的,並且受各種條件的影響,比如,各個環節的配置參數,網絡情況,機器情況,性能測試的工具等等,所以,性能測試的結果往往不能脫離某個環境單獨比較,不同的配置,環境,應用的性能都會呈現出不同的結果,出現問題時,也需要我們從前到後,從上到下仔細分析每一個流程的執行情況,逐步通過工具協助定位,才能最終找到瓶頸。總之,性能測試是一門考驗耐心,細心,知識廣度, 深度的活,每次遇到問題多問幾個為什麼,多做幾次分析和驗證,並嚐試解決,優化它,一定會讓你對係統有更多不一樣的認識。
最後更新:2017-05-23 18:02:32