使用火焰圖做性能分析">使用火焰圖做性能分析

分類:IT技術 時間:2017-10-01

系統性能的評估維度可能很多,包括應用的吞吐量、響應時間、任務完成時間和資源利用率等。但是這些指標(metrics)僅僅是表象,一旦發現異常,如何從代碼級別定位性能問題才是解決問題的關鍵,本文介紹了一種使用 火焰圖(Flame Graph) 來做性能分析的方法,在實戰中具備很高的可操作性和快速pinpoint問題的能力。

下面按照1. 發現問題,2. 分析問題,3. 解決問題三個章節展開,最後是4. Lesson Learned。

1. 發現問題

最近公司完成大數據集群的遷移,應用大多是Spark開發的,但是仍然存在一個老的每日運行的Hadoop任務突然發現指標異常,主要體現在

1. 任務完成時間超長。超過一天仍未完成。

2. CPU占用率幾乎到達100%。由於Hadoop集群label化了,所以只在一個子集的node節點上會運行該程序,暫時和其他應用隔離開來,使用 Zabbix + Grafana 收集的CPU占用率指標如下圖。

放大中間部分,可以看出每臺機器的CPU都基本吃滿了。

2. 分析問題

由於該Hadoop程序已穩定運行N年,代碼一直沒動,所以排除人為bug導致。另外的變量就是集群環境的變化,由於新集群的機器配置都比較高,48核CPU+256G內存,而程序設置的mapreduce.map.memory.mb和mapreduce.map.cpu.vcores參數都保持不變,導致一臺物理機器上可運行的實例數比之前多了很多,CPU資源不足,所以打滿了CPU。

那麽被動的去調整資源,不如深入去主動的尋找程序中的優化點,以提高資源利用率,畢竟資源都是要燒錢的。

老的Hadoop程序業務邏輯很復雜,真去深究恐怕收獲不大,所以要考慮一種“一擊致命”的方案,pinpoint癥結即可。

此時火焰圖登場,火焰圖,英文叫做Flame Graph,是Brendan Gregg發明的,詳細看大師的 博客 。

這裏簡短介紹,火焰圖可以提供可視化的性能分析能力,可以迅速定位最熱的code-path,以SVG的格式的圖片展示,可縮放查看局部。火焰圖支持不同的分析類型,包括CPU、Off-CPU、內存等等,本文遇到的問題由於CPU是瓶頸,故主要采用CPU這種類型做性能分析。火焰圖使用一些系統工具來做采樣收集數據,例如linux上用perf, systemTap ,Windows用Xperf.exe,然後對收集的數據進行處理、轉化、最終渲染成一張SVG圖片。

本文遇到的問題是生產環境直接CPU滿負荷,如果在實際測試系統中可以采用 ab 等工具壓測模擬,一般瓶頸不是CPU就是I/O,如果壓力很大CPU仍然有富余,那麽就需要看下Off-CPU類型的分析,看I/O卡在哪。

下圖就是一張我壓測一個Jetty HTTP Server的CPU類型的火焰圖,火焰圖展示了在采樣周期內,code-path被執行的時間占比,縱軸是code-path,從下至上一般就是調用棧,相同的采樣調用棧會被合並,棧頂元素就是采樣的時候CPU運行的stack,橫軸是某個stack的占用時間,跨度越大說明其占CPU比重越高,也就是最耗費CPU的,stack在橫軸上是按照字母序排列的,顏色深淺僅僅是為了區分,並沒特殊意義。

上圖可以看出很多“尖峰”,這算是比較正常的案例。需要特別關註火焰圖中的“ 平頂山 ”,往往代表著某段代碼的調用占用CPU過多。

那麽如何收集一個Hadoop或者Spark作業的火焰圖呢?我的思路是首先在某臺機器上安裝 SystemTap ,然後使用Jeremy Manson提供了一個工具 Lightweight Asynchronous Sampling Profiler 生成一個so,在Hadoop或者Spark作業的Java_OPTS上加上agent參數,對class字節碼進行instrumentation,從而監控JVM程序的運行,輸出采樣數據,也就是stack trace采樣,最後使用Brendan Gregg的 Flame Graph工具 生成SVG圖片。

Step1. 安裝SystemTap

我的環境是ubuntu,安裝步驟 參考鏈接 ,只需要執行 Systemtap InstallationWhere to get debug symbols for kernel X? 這兩部分的步驟即可。

然後驗證下是否安裝成功,執行如下打印hello world即可。

sudo stap -e 'probe kernel.function("sys_open") {log("hello world") exit()}'

Step2. 生成agent文件

Jeremy Manson提供了一個工具 Lightweight Asynchronous Sampling Profiler 。目前只支持hotspot JVM,可以從 git clone https://github.com/dcapwell/lightweight-java-profiler ,然後執行make all。註意可以在src/globasl.h中設定參數。

// 每秒采樣點數
static const int kNumInterrupts = 100;
 
// 最大采樣的stack數量
static const int kMaxStackTraces = 3000;
 
// 一個采樣stack的最大深度
static const int kMaxFramesToCapture = 128;

Step3. 修改Hadoop或者Spark作業參數

在JAVA_OPTS中加入如下參數。其中liblagent.so就是Step2. make all之後,在build-64目錄下生成的文件。

-agentpath:path/to/liblagent.so

如果只在某些機器上安裝了so,而分布式作業,往往是成百上千的Task並行執行,那麽可以調整max failure percentage,即使某些task fail fast,那麽也不影響采樣,例如Hadoop的參數是mapreduce.map.failures.maxpercent,可以設置成99。Spark 2.2.0中可以嘗試spark.task.maxFailures參數。

註意啟動之後,會在啟動目錄下生成空的traces.txt文件,只有程序執行完畢才會把采樣數據寫入文件,所以在程序運行期間做一個鏈接,使用ln命令即可,這樣即使task執行完畢被YARN clean up,也不至於丟掉采樣數據。

Step4. 生成火焰圖

使用Brendan Gregg的 Flame Graph工具 生成SVG圖片。

git clone http://github.com/brendangregg/FlameGraph
cd FlameGraph
./stackcollapse-ljp.awk < ../traces.txt | ./flamegraph.pl > ../traces.svg

我司內有問題的Hadoop作業的火焰圖如下,正如猜測,“ 平頂山 ”清晰可見,幾乎都是用戶自己的代碼類,最右邊很細條的是Hadoop類的調用棧,基本不占用CPU,可以通過stack清晰的看到究竟是什麽類的、什麽方法瘋狂的占用了CPU,從而 有的放矢的進行優化

由於解決的思路比較trivial,並且涉及公司內的應用,所以暫且簡單說下,我們的程序會使用一個DSL來做數據的過濾,每天過濾的row高達8000億條記錄,而DSL的嵌套又會加劇調用次數,數據無schema,在運行時做Json解析,所以大量的CPU都在做Json解析,可以看到棧頂都是util.HashMap#get(..)方法。另外,不合理的使用Java的集合框架,也是加劇了性能的惡化,例如會看到util.ArrayList#add(..)擴容上浪費了很多CPU時間。

3. 解決問題

這個章節不過多展開,因為一旦定位了問題,總會有辦法解決的,關鍵就是用火焰圖幫助我們大海撈針式的一擊致命找到癥結。

代碼層面的解決方案如下: 

1)數據序列化方式改進。使用Protocol Buffer代替Json,避免運行時做低效的反序列化。

2)DSL的過濾分為邏輯執行計劃,和物理執行計劃兩部分,在邏輯執行計劃內做優化,flatten化多個同樣的過濾函數,最優化CPU pipeline,減少調用次數。

3)List的新建加入initial capacity,防止膨脹拷貝。

資源調整方面的解決方案如下:

1)合理設置mapreduce.map.memory.mb和mapreduce.map.cpu.vcores參數,讓資源充分利用,並且不至於壓垮機器。

優化後,從Grafana上的截圖可以看出,整個作業的運行時間不僅CPU占用降低了,而且整體的運行時間也縮短了。

放大局部,占用率保持在85%左右,最大化資源利用率。

4. Lesson Learned

解決問題的能力非常重要,問題雖然千變萬化,但是發現他們的手段無非就幾種,各種profiling,debugging和tuning工具都可以對應用進行全面的“體檢”,包括CPU、內存、網絡I/O等,通過這些具體system/application level的指標監控,可以發現問題的癥結。本文中沒有采用JVM的一些常用的內存和進程分析工具,轉而使用火焰圖,所以一下就可以找到問題。解決問題的思路,第一,優化應用本身,可以通過代碼級別,或者像Hadoop/Spark作業,算子的合理使用也可以大大提升性能,第二,優化資源調參,這需要建立在對building blocks和自己開發的應用程序有一定的認識和理解上。

總之,發現問題不可怕,可怕的是找不到根源,希望本文可以給讀者一種思路,通過一個特定的性能分析工具集,可以幫助我們pinpoint問題,從而不斷的縮小搜索範圍,最終定位問題,做有針對性的優化。

參考資料

http://www.brendangregg.com/flamegraphs.html

https://www.slideshare.net/brendangregg/blazing-performance-with-flame-graphs

https://huoding.com/2016/08/18/531

http://tacy.github.io/blog/2014/07/16/FlameGraph/

http://dmdgeeker.com/post/flamegraph/

轉載時請註明轉自neoremind.com。 


Tags: 問題 集群 性能分析 用率 程序 資源

文章來源:


ads
ads

相關文章
ads

相關文章

ad