當您的線上應用出現CPU、記憶體資源使用率高或大量慢調用問題時,可以通過ARMS持續剖析功能產生的火焰圖對其進行根因定位。本文介紹如何通過持續剖析功能的火焰圖定位效能瓶頸。
什麼是火焰圖
火焰圖(Flame Graph)是一種可視化程式效能分析工具,它可以協助開發人員追蹤程式的函數調用以及調用所佔用的時間,並展示對應資訊。
其核心思想是將程式的函數調用方法棧轉化為一個矩形的火焰形映像,每個矩形的寬度表示該函數對應資源使用佔比,高度表示函數整體的調用深度。通過對比不同時間點的火焰圖,可以快速診斷程式的效能瓶頸所在,從而有針對性地進行最佳化。
火焰圖類型
廣義上的火焰圖畫法分為2種,分別是函數方法棧棧底元素在底部,棧頂元素在頂部的狹義火焰圖,如下圖1所示;以及方法棧棧底元素在頂部,棧頂元素在底部的冰柱狀火焰圖,如下圖2所示。
圖1.狹義火焰圖
圖2.冰柱狀火焰圖
使用火焰圖
火焰圖作為效能分析的可視化技術,只有理解它才能基於其做效能分析。例如,對於一張CPU熱點火焰圖,通過查看火焰圖中是否有較寬的棧頂,即可瞭解CPU中是否存在耗時較長的函數。
因為火焰圖所繪製的內容就是電腦中方法執行的方法棧。而電腦中函數的調用上下文是基於一個叫做棧的資料結構去儲存,棧資料結構的特點是元素先進後出,因此棧底就是初始調用函數,依次向上就是一層層的被調用的子函數。當最後一個子函數也就是棧頂執行結束後才會依次從上往下出棧,因此棧頂較寬,就表示該子函數執行時間長,其下方的父函數也會因其一直執行無法即時出棧而導致最終整體耗時較長,具體過程如下圖所示:
分析火焰圖的方法步驟如下:
判斷火焰圖對應的類型,找到其中的棧頂方向。
如果火焰圖總資源佔用高,就繼續檢查火焰圖的棧頂是否有較寬的部分。
如果存在較寬的棧頂,沿著棧頂依次往棧底方向搜尋,找到第一個包名為所分析應用自身定義的方法行,然後重點排查該方法是否存在最佳化空間。
實踐分析
ARMS持續剖析功能通過火焰圖可視化技術呈現應用的效能剖析資料,當線上應用出現CPU、記憶體資源使用率高或大量慢調用問題時,可以通過該功能產生的火焰圖對其進行根因定位,從而協助開發人員最佳化程式、降低延遲、增加吞吐、節約成本。如果還未接入持續剖析功能,請參考接入持續剖析功能完成接入。
下圖為一張資源佔用較高的火焰圖,火焰圖中效能瓶頸的具體分析步驟如下:
通過火焰形狀可以判斷這是一張棧底在上,棧頂在下的冰柱狀火焰圖,因此需要從下往上分析。
分析下方的棧頂,可以發現右側較寬的棧頂為java.util.LinkedList.node(int)方法。
由於該棧頂是JDK中的庫函數,並非為業務方法,因此,沿著棧頂方法java.util.LinkedList.node(int)從下往上搜尋,依次經過java.util.LinkedList.get(int) > com.alibaba.cloud.pressure.memory.HotSpotAction.readFile(),而com.alibaba.cloud.pressure.memory.HotSpotAction.readFile()屬於所分析應用的業務方法,即為第一個所分析應用自身定義的方法行,其耗時為3.89s,占整張火焰圖的76.06%,因此com.alibaba.cloud.pressure.memory.HotSpotAction.readFile()是該火焰圖所採集時段內資源佔用較高的顯著瓶頸所在,可以根據該方法名,對業務中相關方法的邏輯進行梳理,查看是否存在最佳化空間。
另外也可以根據上述分析方法對火焰圖左下角java.net.SocketInputStream的相關方法進行相同分析,可以發現其第一個屬於所分析應用自身定義的父方法為com.alibaba.cloud.pressure.memory.HotSpotAction.invokeAPI,總佔比約為23%。