解密 ARMS 持續剖析:如何用一個全新視角洞察應用的性能瓶頸?

作者:饒子昊、楊龍

應用複雜度提升,根因定位困難重重

隨着軟件技術發展迭代,很多企業軟件系統也逐步從單體應用向雲原生微服務架構演進,一方面讓應用實現高併發、易擴展、開發敏捷度高等效果,但另外一方面也讓軟件應用鏈路變得越來越長,依賴的各種外部技術越來越多,一些線上問題排查起來變得困難重重。

儘管經過過去十幾年的發展,分佈式系統與之對應的可觀測技術快速演進,在一定程度上解決了很多問題,但有一些問題定位起來仍然很喫力,如下圖是幾個非常有代表性的線上常見問題:

圖 1 CPU 持續性出現波峯

圖 2 堆內存空間用在了哪裏

圖 3 Trace調用鏈無法定位到耗時根因

針對上述問題,該如何進行根因定位?

對於一些問題排查經驗比較資深,各種排查工具接觸比較多的朋友可能會分別針對上述問題想到如下排查定位方法:

  1. 針對 CPU 波峯診斷,使用 CPU 熱點火焰圖工具進行問題排查;

  2. 針對內存問題可通過內存快照來進行內存使用診斷;

  3. 針對慢調用鏈診斷過程中出現耗時缺失問題,可以使用 Arthas 提供的 trace 命令進行方法耗時診斷。

上述方案確實有時候可以解決一部分問題,但有過相關問題排查經驗的朋友一定也清楚,其分別有各自的使用門檻和侷限性,比如:

  1. 針對測試環境難以復現的線上問題,CPU 熱點火焰圖工具也無能爲力;

  2. 內存快照不僅對線上應用運行穩定可能有影響,而且需要有比較強的相關工具使用分析經驗纔可能診斷得出問題來;

  3. Arthas 的 trace 命令在慢調用鏈不是穩定復現難以跟蹤情況下問題排查就變得很困難,另外,針對跨多應用,多臺機器的調用請求定位過程也非常困難等。

持續剖析,一個全新應用洞察視角

那有沒有一種比較簡單又高效的強大診斷技術能幫助我們解決上述問題呢?答案就是本文接下來要介紹的持續剖析技術。

持續剖析是什麼?

持續剖析(Continuous Profiling)是通過動態實時採集應用程序 CPU/內存等資源申請的堆棧信息,來幫助監測和定位應用程序的性能瓶頸。通過上述介紹,大家對持續剖析的概念是不是還是比較模糊?如果說之前很多朋友沒聽說過持續剖析,那 JDK 提供的 jstack 打印線程方法棧,定位現程狀態這個工具可能有很多朋友在過往排查應用問題的時候或多或少都可能接觸過:

圖 4 jstack 工具

持續剖析其實思想跟 jstack 類似,它也是以一定頻率或者閾值抓取應用線程執行的 CPU、內存等資源申請使用方法棧信息,然後通過一些可視化技術將相關信息呈現出來,讓我們能比較直觀地洞察到應用相關資源使用情況。說到這裏,可能性能分析工具使用比較多的朋友會聯想到火焰圖:

圖 5 火焰圖工具

平時在壓測過程中,通過手動開啓或關閉使用的一次性性能診斷工具如 Arthas CPU 熱點火焰圖生成工具其實是一類即時剖析技術,它無論從採集數據的方法與數據呈現形式,跟將介紹的持續剖析技術基本無二。相比於持續剖析,最核心的區別在於它是即時而非“持續”的。

有過火焰圖使用經驗的朋友,大家回憶一下,日常我們使用 CPU 熱點火焰圖工具一般都是在壓測場景,通過一些工具在壓測過程中抓取應用一段時間的火焰圖做壓測性能分析。而持續剖析不僅僅是解決壓測場景的性能觀測,更重要的是它通過一些技術優化能以低開銷的方式,伴隨着應用整個運行生命週期,持續地剖析應用的各種資源使用情況,然後通過火焰圖或者其他可視化方式爲我們呈現出相比可觀測技術,更底層更深入的可觀測效果。

持續剖析實現原理

說完持續剖析基本概念,大家一定對持續剖析的實現原理有所好奇,接下來簡單介紹一些相關實現原理。我們知道 Tracing 通過對關鍵執行路徑上方法埋點採集調用中的信息,來還原調用中參數/返回值/異常/耗時等信息,但業務應用難以窮舉所有埋點,另外埋點太多開銷也會很大,因此難以完全覆蓋全面纔會出現上文介紹的圖 3 Tracing 監控盲區問題。而持續剖析的實現其實是在更底層對一些資源申請相關 JDK 庫關鍵位置進行埋點或者依賴於操作系統特定事件來實現信息採集,不僅可以實現低開銷而且所採集的信息具有更強的洞察力效果。

比如 CPU 熱點剖析,其大致思路,通過操作系統底層的系統調用獲得 CPU 上執行線程的信息,然後以一定頻率(比如 10ms)採集一個線程對應的方法棧信息,1s 中就可以採集 100 個線程方法棧信息,類似下圖 6一樣,最後將這些方法棧做一些處理,最後再利用一些可視化技術比如火焰圖展示出來,就是 CPU 熱點剖析結果了。當然上述只是簡單說了一些實現原理,不同的剖析引擎以及所需要剖析的對象在技術實現上一般也有些許差異。

圖 6 持續剖析數據採集原理

除了常見的 CPU 熱點火焰圖剖析,其實對計算機中的各種系統資源的使用和申請,都可通過持續剖析技術提供對應的剖析結果來幫助分析相關資源的申請和實現原理簡介(注意,不同的剖析實現技術可能會有差異):

功能域 剖析類型 實現原理簡介
CPU CPU耗時 以一定頻率記錄線程在Runnable狀態下的方法棧
內存 堆內存分配大小 記錄線程每個觸發堆內存分配閾值時的內存分配大小以及觸發時刻的方法棧
直接內存分配大小 記錄線程每個觸發直接內存分配閾值時的直接內存分配大小以及觸發時刻的方法棧
堆存活對象分配大小 記錄線程每個觸發堆內存中分配閾值時且尚未被垃圾回收的對象大小以及觸發時刻的方法棧
耗時 牆鍾 以一定頻率記錄線程在任意狀態下的方法棧
鎖等待耗時 線程等待鎖資源耗時達到閾值後記錄相關耗時及線程對應方法棧
IO Socket I/O讀寫耗時 線程等待讀寫Socket I/O 資源耗時達到閾值後記錄相關耗時及線程對應方法棧
Socket I/O讀寫數據量 線程等待讀寫Socket I/O 數據量達到閾值後記錄相關數據量及線程對應方法棧

持續剖析可視化技術

之前說了很多關於持續剖析的內容,也提到了火焰圖,在持續剖析採集後的數據可視化方面,應用最爲廣泛的技術之一便是火焰圖(Flame Graph)那火焰圖又有哪些奧妙之處呢?

什麼是火焰圖?

火焰圖是一種可視化程序性能分析工具,它可以幫助開發人員追蹤程序的函數調用以及調用所佔用的時間,並且展示出這些信息。其核心思想是將程序的函數調用方法棧轉化爲一個矩形的 “火焰” 形圖像,每個矩形的寬度表示該函數對應資源使用佔比,高度表示函數整體的調用深度。通過比較不同時間點的火焰圖,可以快速診斷程序的性能瓶頸所在,從而針對性地進行優化。

廣義上的火焰圖畫法分爲 2 種,分別是函數方法棧棧底元素在底部,棧頂元素在頂部的狹義火焰圖,如下左圖所示,以及方法棧棧底元素在頂部,棧頂元素在底部的冰柱狀火焰圖,如下右圖所示。

圖 7 各種類型火焰圖

如何使用火焰圖?

火焰圖作爲性能分析的可視化技術,只有理解它該如何讀才能基於其做性能分析。比如對於一張 CPU 熱點火焰圖,對於這個問題經常聽到的一個說法就是看看火焰圖中是否有較寬的棧頂,這個說法背後的原因是什麼呢?

其實是因爲,火焰圖所繪製的內容就是計算機中方法執行的方法棧。而計算機中函數的調用上下文是基於一個叫做棧 [ 1] 的數據結構去存儲,棧數據結構的特點是元素先進後出,因此棧底就是初始調用函數,依次向上就是一層層的被調用子函數。當最後一個子函數也就是棧頂執行結束以後纔會依次從上往下出棧,因此棧頂較寬,就表示該子函數執行時間長,其下方的父函數也會因爲其一直執行無法即時出棧而導致最終整體耗時很長。

圖 8 棧數據結構

因此分析火焰圖的方法步驟如下:

  1. 判斷火焰圖對應的類型,找到其中的棧頂方向;

  2. 如果火焰圖總資源佔用高,就繼續檢查火焰圖的棧頂是否有較寬的部分;

  3. 如果存在較寬的棧頂,沿着棧頂依次往棧底方向搜索,找到第一個包名爲所分析應用自身所定義的方法行,然後重點排查該方法是否存在優化空間。

以下爲一張資源佔用高的火焰圖,具體分析火焰圖中的性能瓶頸步驟如下:

  1. 由下圖形狀可發現爲一張棧底在上,棧頂在下的冰柱狀火焰圖,因此需要從下往上分析。

  2. 分析下方的棧頂,可以發現右側較寬的棧頂爲右側的方法:java.util.LinkedList.node(int)。

  3. 由於該較寬棧頂是 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%,因此其是該火焰圖所採集時段內資源佔用較高的最大瓶頸所在,因此可以根據相關方法名,對業務中相關方法的邏輯進行梳理,看是否存在優化空間。另外也可根據上述分析方法對圖的左下角 java.net.SocketInputStream 相關方法一樣進行分析,發現其屬所分析應用第一個自身所定義的父方法全限定名爲:com.alibaba.cloud.pressure.memory.HotSpotAction.invokeAPI,總佔比位約爲 23%。

圖 9 火焰圖分析過程

開箱即用的 ARMS 持續剖析能力

經過上面的介紹,這個時候大家無論是對持續剖析概念、數據採集原理以及可視化技術應該都有了一定了解。然後,再介紹一下 ARMS 提供的開銷即用持續剖析能力,如何幫助排查定位各類線上問題。

ARMS 提供一站式持續剖析產品能力,已經有接近 1w 應用實例在線上開啓該功能進行持續數據採集與監控。

圖 10 ARMS 持續剖析產品能力

左測圖是當前 ARMS 持續剖析能力的概覽,從上往下依次是數據採集、數據處理以及數據可視化。具體功能層面,目前針對用戶需求最爲急迫的幾個場景分別提供了對應解決方案,比如 CPU、堆內存分析,提供了 CPU、內存熱點功能。針對慢調用鏈診斷問題,ARMS 提供了代碼熱點功能。ARMS 上的持續剖析是 ARMS 團隊聯合阿里雲 Dragonwell 團隊一起研發的持續剖析產品能力,相比於一般的剖析方案,它具有開銷低、粒度細和方法棧完備等特點。

使用介紹

在 ARMS 產品文檔已經提供對應子功能的最佳實踐內容:

  • 針對 CPU 利用率高問題診斷,可以參考《使用 CPU 熱點診斷 CPU 消耗高問題 [ 2] 》進行問題診斷。
  • 針對堆內存利用率高問題診斷,可以參考《使用內存熱點診斷堆內存使用高的問題 [ 3] 》進行問題診斷。
  • 針對調用鏈耗時根因診斷,可以參考《使用代碼熱點診斷慢調用鏈的問題 [ 4] 》進行問題診斷。

客戶案例

相關功能自發布以後,較好地協助用戶對一些線上困擾已久的疑難雜症進行診斷,獲得很多用戶的好評,例如:

  1. 用戶 A,發現某個應用服務剛啓動的時候,前幾個請求會很慢,使用 Tracing 出現了監控盲區無法診斷耗時分佈。最後,使用 ARMS 代碼熱點,幫助其診斷出相關慢調用鏈的耗時根源是 Sharding-JDBC 框架初始化耗時所致,幫助其終於搞清楚了一直困擾的現象根因。

圖 11 用戶問題診斷案例 1

  1. 用戶 B,壓測過程中,應用的所有實例中總會出現有部分節點響應時長比其它節點慢很多,使用 Tracing 也看不出根因。最後,通過代碼熱點發現相關應用實例一壓到某個壓力情況下就會出現大量的時間消耗在寫日誌上,然後,根據相關信息,排查應用環境日誌採集組件的資源使用率,發現其壓測過程中佔用了大量 CPU,導致應用實例寫日誌爭搶不到資源而導致請求處理慢。

圖 12 用戶問題診斷案例 2

  1. 用戶 C,線上應用運行過程中,發現堆內存使用量總是很大,通過內存熱點,很快發現是應用使用的該版本微服務框架運行過程中將訂閱的上游服務信息進行持久化處理導致大量堆內存佔用,然後諮詢相關框架服務提供方,最後,瞭解到可通過升級框架版本解決該問題。

圖 13 用戶問題診斷案例 3

開銷情況

最後,大家可能會 ARMS 持續剖析開銷非常關心,我們設計瞭如下壓測場景對該功能開銷進行測算,其模擬了一個從壓測中心發起請求打入到業務入口應用,該應用會查詢查詢數據庫並返回結果。

圖 14 壓測示意圖

測試環境開啓所有的持續剖析功能,採用的 K8s 容器運行環境來模擬一般企業應用運行環境。Pod limit 值爲 4c8g,4g 堆內存年輕代佔比設置爲 1/2,壓力極限爲 6000 TPS。分別測試 500TPS 和極限壓力的 80% 4800TPS 情況下的開銷如下表所示。從表中可以看到,全部功能開啓後 CPU 開銷在 5% 左右,堆內內存開銷不明顯,堆外內存佔用爲 50MB 左右,流量小,或者僅開啓部分持續剖析功能的情況下會更低。

圖 15 壓測結果

據瞭解,很多企業應用運行過程中的 CPU/內存等資源利用率都是比較低,通過少量資源消耗,爲應用提供一個全新的觀測視角,讓應用在運行異常時有詳細的根因定位數據還是非常有價值的!

如果您對文中提到的 ARMS 中的持續剖析功能感興趣,歡迎加入 ARMS 持續剖析(Continuous Profiling)產品能力交流釘釘羣討論。(羣號:22560019672

直播推薦:

掌握 ARMS 持續剖析-輕鬆洞察應用性能瓶頸:https://developer.aliyun.com/live/253768

相關鏈接:

[1] 棧

https://baike.baidu.com/item/%E6%A0%88/12808149

[2] 使用 CPU 熱點診斷 CPU 消耗高問題

https://help.aliyun.com/zh/arms/application-monitoring/user-guide/using-cpu-hotspots-to-diagnose-high-cpu-consumption

[3] 使用內存熱點診斷堆內存使用高的問題

https://help.aliyun.com/zh/arms/application-monitoring/user-guide/using-memory-hotspots-to-diagnose-high-heap-memory-usage

[4] 使用代碼熱點診斷慢調用鏈的問題

https://help.aliyun.com/zh/arms/application-monitoring/user-guide/use-code-hotspots-to-diagnose-code-level-problems

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章