【初探】java性能火焰圖的生成


一、前言

開始之前,你需要准備的環境:

Linux系統機器或者虛擬機一台,里面需要安裝的軟件:git、jdk、perl


二、簡單介紹

java性能分析火焰圖的所做的事情就是能夠分析出java程序運行期間存在的性能問題,因為某段代碼拖慢整個程序執行是不允許的,因此靠火焰圖的繪制和分析就可以找出類似的“問題代碼段”。

那么這個圖是怎么來的呢?首先跟大多數監控系統一樣,數據采集+前端繪圖,這個圖也是根據某些數據繪制而成的,繪圖工具本篇文章采用FlameGraph,而負責收集這些數據的工具,本篇采用async-profiler,這個工具會在程序運行期間向jvm發送信號采集其運行期數據(簡單來說就是通過該工具可以找出程序中占用CPU資源時間最長的代碼塊,這里async-profiler的實現使用了jvmti,戳這里簡單了解一下),然后生成相應的數據格式文件,而FlameGraph則負責讀取和解析數據文件生成對應的火焰圖(svg文件)。


三、使用&安裝

🔥3.1:環境搭建

確認你的機器已經安裝了git、jdk、perl、c++編譯器,部分可參考:安裝雜記

🔥3.2:clone相關項目

下載下來所需要的兩個項目(這里建議放到data目錄下):


git clone https://github.com/jvm-profiling-tools/async-profiler
git clone https://github.com/brendangregg/FlameGraph

🔥3.3:編譯

下載好以后,需要打開async-profiler文件,輸入make指令進行編譯:


cd async-profiler
make

🔥3.4:編寫測試程序

編譯完成后,我們來寫一個簡單的java程序:


public class Test {

    public static void main(String[] args) throws Exception {
        Test test = new Test();
        while (true) {
            test.func1();
            test.func2();
            test.func3();
        }
    }

    public void func1() throws Exception { //調用第一個方法,需要100ms
        Thread.sleep(100L);
    }

    public void func2() throws Exception { //調用第二個方法,需要500ms
        Thread.sleep(500L);
    }

    public void func3() throws Exception { //調用第三個方法,需要1500ms
        Thread.sleep(1500L);
    }

}

非常簡單的一個java類,main方法里所做的事情也很簡單,現在把這個文件搞到data目錄下,javac命令編譯,java命令啟動。

然后找到這個java程序的進程id:


ps -ef | grep java
root     30937 17605  0 19:12 pts/0    00:00:00 java Test
root     30961 23135  0 19:12 pts/1    00:00:00 /bin/grep --color=auto java

可以確認此時Test類運行時的java進程 pid = 30937,當然也可以使用jps命令直接查看java進程,效果是一樣的。

🔥3.5:生成火焰圖數據

ok,上述步驟完成后,現在進入async-profiler那個項目的目錄下,然后輸入如下指令:


./profiler.sh -d 60 -o collapsed -f /tmp/test_01.txt ${pid}

上面的-d表示的是持續時長,后面60代表持續采集時間60s,-o表示的是采集規范,這里用的是collapsed,-f后面的路徑,表示的是數據采集后生成的數據存放的文件路徑(這里放在了/tmp/test_01.txt),${pid}表示的是采集目標進程的pid,也就是上面提到的30937

回車運行,運行期間阻塞,知道約定時間完成。運行完成后,現在去tmp下看看有沒有對應文件:

🔥3.6:生成svg文件

上一步產生的文件里的內容,肉眼是很難看懂的,所以現在FlameGraph的作用就體現出來了,它可以讀取該文件並生成直觀的火焰圖,現在進入該項目目錄下面,執行如下語句:


perl flamegraph.pl --colors=java /tmp/test_01.txt > test_01.svg

因為是perl文件,這里使用perl指令運行該文件,后面--colors表示着色風格,這里是java,后面的是數據文件的路徑,這里是剛剛上面生成的那個文件/tmp/test_01.txt,最后的test_01.svg就是最終生成的火焰圖文件存放的路徑和文件命名,這里是命名為test_01.svg並保存在當前路徑,運行后看到該文件已經存在於當前目錄下:

🔥3.7:展示

現在下載下來該文件,使用瀏覽器打開,效果如下:

果然還是看不懂啊-_-||

后續會更新這東西怎么看和分析,或者說我這篇文章里的java例子可能並不能很好的體現出什么。


續更

續更,公司內部火焰圖已經上線,通過更為復雜的業務場景生成的圖反而看起來更容易理解一些,因為業務代碼的調用也會打印出來,下面貼一下內部某業務系統火焰圖:

這張圖是在某個業務系統運行時,采樣60s生成的火焰圖,通過這樣一張圖可以看出,x軸為調用順序,y軸為棧深,線條顏色無實際意義(並不是越紅性能越差之類的),線條長度代表CPU執行該方法時所花費的時間占比,一般來說需要關注的就是棧頂,且寬度比較大的那個。因為一般處於棧頂的,而且寬度比較大的調用棧,說明其存在性能問題,這樣分析的原因如下:

棧深度與y軸高度成正比,一般造成性能問題的都在調用棧的棧頂位置,因為棧頂位置的性能問題會間接拖慢整個調用棧,比如上圖中每個棧底的線條都很長,這是因為越往上棧越深,對下層的影響就越大,可以簡單抽象成方法調用:A調用B,B調用C,C慢會間接導致B慢,從而導致A慢,當然符合這種情況就適合之前說的看棧頂分析瓶頸的方法,如果A本身就慢呢?通過火焰圖也是可以看出來的,比如棧底的線條寬度很寬,但是建立在該棧底的調用鏈上,線條都很窄,火焰圖呈現“┻”型,那么就可以認定,棧底方法存在性能問題,一般情況下都是從棧頂看起,視情況而定~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM