使用 Health Center 優化應用程序
快速並輕松地修復性能問題、識別配置問題並監控 Java 應用程序
簡介:IBM Monitoring and Diagnostic Tools for Java™ - Health Center 是一個用於監控 一個正在運行的 Java 應用程序的工具。它通過圖表、曲線圖和表全面報告系統健康狀況,並就如何修復 問題提供建議。Health Center 包含一個開銷極低的方法配置程序(profiler)、一個垃圾收集可視化程 序和一個鎖定配置程序,用於識別爭用瓶頸;它還包含一個配置浏覽器。了解如何使用這個工具診斷和修 復應用程序中的性能、配置和穩定性問題。
是什麼原因導致我的應用程序產生性能問題?如果我 不是性能專家,如何修復這些問題?我的應用程序穩定嗎?它的配置是否合理?IBM Monitoring and Diagnostic Tools for Java - Health Center 是設計用於解答這些問題和其他相關問題的新工具。它檢 查垃圾收集行為、方法執行、應用程序同步和配置。除了提供問題診斷所需的信息之外,Health Center 中的專家系統還能為您解決問題:提供分析、標記有關區域、提供推薦方法並建議相應的命令行。Health Center 是一個非常輕量級的工具,甚至可以用於生產。本文介紹如何下載和安裝 Health Center,以及 如何使用它對您的應用程序進行故障診斷和故障排除。
Health Center 入門
Health Center 工具包含兩個部分:客戶端 和代理。代理將來自受監控的 JVM 的信息發送到客戶端 。客戶端連接到代理,並在一個 GUI 中顯示正在運行的 Java 應用程序的健康狀況。
JVM 要求
Health Center 設計用於在 Java 5 或更高版本的 IBM JVM 上運行。它需要的 Java 版本至少為 Java 5 service refresh 8 或 Java 6 service refresh 1。為了用於生產,您需要 Java 5 service refresh 10 或 Java 6 service refresh 5。
安裝客戶端
Health Center 客戶端是 IBM Support Assistant (ISA) 的一部分。要安裝客戶端,請執行以下步驟 :
下載 並安裝 ISA Workbench。
啟動 ISA Workbench,從菜單欄選擇 Update > Find New... > Tools Add-ons。
在 Find new tools add-ons 向導的搜索框中輸入 health,然後展開 JVM-based Tools 旁邊的 Twistie 以顯示 Health Center 條目,如圖 1 所示。
圖 1. 在 ISA 中安裝 Health Center 客戶端
選擇 Health Center 條目,單擊 Next,根據提示完成安裝過程,然後啟動 ISA。
安裝代理
安裝客戶端後,必 須從客戶端中下載代理並安裝:
單擊 ISA Welcome 頁面上的 Analyze Problem。
選擇 Tools 子選項卡。從已安裝工具列表中選擇 IBM Monitoring and Diagnostic Tools for Java - Health Center 並單擊 Launch,這將打開 Health Center 連接向導,如圖 2 所示。
圖 2. 連接向導
單擊 Enabling the application for monitoring 鏈接。
在下一頁面上,單擊 Installing the Health Center agent into an IBM JVM。
在 Installing the Health Center agent into an IBM JVM 頁面上, 單擊與您的系統上的 JVM 對應的鏈接,以下載代理文件的壓縮文檔。
將該壓縮文檔解壓縮到要監 控的 JVM 的根目錄中。從 Java 6 service refresh 2 和 Java 5 service refresh 8 開始,Health Center 代理就包含在 JVM 中。但是,這個代理可能不是最新版本,因此,最好使用新版本覆蓋現有的 Health Center 代理。如果安裝過程中提示是否覆蓋文件,請選擇 yes。
啟動要監控的應用程序
要使用 Health Center 監控一個應用程序,您必須使用一個啟用 Health Center 代理的命令行 選項啟動該應用程序。選項語法取決於您的 JVM 版本:
對於 Java6 SR5 和以上版本,使用 -Xhealthcenter。
對於 SR1 和以上版本,使用 -agentlib:healthcenter -Xtrace:output=perfmon.out 選項。
對於 Java 5、SR10 和以上版本,使用 -Xhealthcenter。否則,使用 -agentlib:healthcenter - Xtrace:output=perfmon.out。
如果您不知道自己的 Java 版本號,可以通過運行 java -version 命令將版本號輸出到控制台,如圖 3 所示。
圖 3. 獲取 Java 版本號
要確定使用哪個命令選項來啟用代理,一個簡單的方法是首先嘗試 -Xhealthcenter 選項。如果不行 ,再嘗試 -agentlib:healthcenter -Xtrace:output=perfmon.out。
如果在您的應用程序啟動時,Health Center 代理也成功啟動,控制台上將顯示一條消息。例如,如 圖 4 顯示,當我們使用 -Xhealthcenter 選項運行 java -version 時,Health Center 代理在端口 1972 上啟動。代理通常監聽端口 1972,但如果該端口已被使用(比如另一個 Health Center 代理), 該代理將自動遞增端口號。
圖 4. 運行 java -version 並啟用 Health Center
一旦代理啟動,您就可以使用 Health Center 客戶端監控您的應用程序並解決各種性能和配置問題。
示例 1:修復一個性能問題
性能優化必須以具體證據為依據。通過檢查應用程序代碼來識別潛在的性能改進並直接進行修復固然 很容易也很誘人,但是,不成熟的優化可能會降低生產率,甚至很危險。與更慢但更自然的代碼相比,優 化後的代碼通常更難以維護。而且,進行這些優化也會耗費大量時間。如果性能的確得到改進,那麼優化 成本和高度優化的代碼所需的額外維護工作仍然是值得的;然而,許多優化並沒有取得任何性能改進效果 。優化必須瞄准那些能夠產生顯著效果的位置。識別優化會在哪些位置產生顯著效果的過程也是發現瓶頸 的過程。
分析性能問題
本質上,所有性能問題的根源都是因為資源有限。影響性能的幾種基本計算資源是:CPU、內存、I/O 和鎖。一個 CPU 關鍵型應用程序不能得到足夠處理器時間來完成既定工作。一個內存關鍵型應用程序得 不到足夠的內存。一個 I/O 關鍵型應用程序的 I/O 速度無法被系統處理。在一個鎖關鍵型應用程序中, 多個線程在相同的鎖上爭用。線程之間的同步導致了鎖爭用。隨著這些系統變得越來越並行化,同步成為 一個影響它們的伸縮性的限制因素。
通過識別瓶頸,您可以識別哪個資源是有限的。Health Center 有幾個用於檢查和診斷低劣的應用程 序性能的工具。性能分析過程是這樣的:發現瓶頸、修復瓶頸問題,識別下一個瓶頸、修復瓶頸問題,循 環往復,直至獲得滿意的性能。Health Center 自動化用於識別有限資源的多種流程。目前,Health Center 不能分析 I/O 使用情況,但它能為 CPU 使用、內存使用和鎖使用提供形象化顯示和建議。
Health Center 的 Status 透視圖顯示一個帶有狀態指示器的儀表板,每一個潛在的受限資源都有一 個狀態指示器。紅色和橙色狀態表示應用程序性能可以提高的區域。圖 5 顯示打開的 Status 透視圖:
圖 5. Status 透視圖
檢查垃圾收集
過度的垃圾收集(Garbage Collection,GC)是性能低下的一個普遍原因。GC 是 JVM 用於自動管理 應用程序內存的過程。它的好處 — 就代碼安全和簡單性而言,甚至經常就性能而言 — 是巨大的。但是 ,垃圾收集器確實占用處理資源,不當的應用程序內存使用模式和配置不當的堆大小都可能會導致垃圾收 集器成為一個重大的性能瓶頸。
Health Center 提供 GC 行為的詳細形象化顯示和關於 GC 調優的建議。圖 6 顯示了 Health Center 的 Garbage Collection 透視圖,它包含已用堆(用於估計應用程序的內存使用)和暫停時間(用於估計 GC 的性能影響)的形象化顯示,以及一個 GC 統計摘要表和一組推薦方法,其中包括命令行建議(如果 需要的話)。
圖 6. Garbage Collection 透視圖
評估 GC 的性能影響時,需要檢查的最重要的項目是暫停時間和開銷:用於進行垃圾收集而不是執行 應用程序工作的時間的比例。圖 7 展示了 Health Center 計算的 GC 開銷。如果開銷值較高,則應用程 序可用的處理時間就不足。如果暫停時間值較高,則應用程序響應性就低,因為應用程序活動將在 GC 暫 停期間停止。
圖 7. GC 開銷展示表
GC 性能改進策略
GC 的性能影響可以通過幾種方法降低。第一種方法是生成更少的垃圾。應用程序是否創建對象並立即 丟棄這些對象?字符串被反復連接並沒有使用字符串緩沖?自動裝箱(autoboxing)是否在後台創建無關 的原語包裝器嗎?代碼正在生成不需要的大對象嗎?其他性能改進方法包括提高堆大小、調整保育室 (nursery)大小(用於分代收集器)和嘗試另一個 GC 策略。但是,使用這些技術時要小心。
例如,調優代碼以改進 GC 時必須小心。某些明顯的優化可能最終會導致更糟糕的性能。例如,通過 重用現有對象實例來避免重復創建對象看起來很不錯。但是,安全地管理對象池可能會導致同步開銷。如 果對象池大小沒有正確調優,許多未使用的對象實例最終會被閒置,耗盡內存而不產生任何價值。然而, 最嚴重的是,使用一個分代垃圾收集器(比如 gencon 策略所使用的)時,短期存在的對象根本收集不到 ,而長期存在的對象的收集成本則太昂貴。重復創建並丟棄對象的方法產生很小的性能開銷,而持有現有 對象實例以便重用的方法則為垃圾收集器增加大量的工作負擔。
另一個 GC 調優陷阱是過度關注減小 headline GC 開銷(參見 圖 7),而忘記了總體目標是優化應 用程序 的性能。盡管減小 GC 開銷通常會提高應用程序性能,但也有例外情況。例如,使用 gencon 策 略執行 GC 花費的時間通常比使用 optthruput 策略花費的時間更多。但是,由於 gencon 策略在堆中放 置對象的特定方式,該策略支持更快的對象分配和更快的對象訪問。由於應用程序通常花費很多時間來分 配和訪問對象,所以,對多數應用程序來說,在這個區域獲取的性能改進(沒有在 GC 開銷中反映出來) 超出了 GC 本身的額外成本。甚至還有更具戲劇性的例子:optavgpause 策略幾乎能同時執行所有 GC 工 作,只有非常短的 “stop-the-world” 暫停。這導致非常低的 GC 開銷(通常低於 1%)和極好的應用 程序響應性。但是,在應用程序吞吐量方面不如 optthruput 或 gencon 策略。
檢查鎖爭用
當一個鎖當前正在使用,而另一個線程試圖獲取它,那麼就會出現鎖爭用。以下三種鎖會出現較高程 度的爭用:經常獲取的鎖,長期占用的鎖,以及經常使用且長期占用的鎖。一個高度爭用的鎖(許多線程 試圖訪問的鎖)可能會變成系統中的一個瓶頸,因為每個正在運行的線程在其需要的鎖可用之前都會暫停 執行,從而限制了應用程序的性能。同步很可能會阻止應用程序的可伸縮性;系統中的線程數越多,用於 等候鎖而不是執行有用的工作所花費的時間也就越多。Health Center 可視化鎖行為並突出顯示那些正在 阻塞請求且有可能影響性能的鎖。
圖 8 展示了 Health Center 的 Locking 透視圖:
圖 8. Locking 透視圖
要理解圖 8 展示的柱形圖,您需要理解顯示的數據。柱形圖中的豎條用顏色編碼,從綠色到紅色,以 顯示爭用的程度。激烈爭用的鎖顯示為鮮紅色,沒有爭用的鎖顯示為鮮綠色。每個豎條的高度(相對於其 他豎條)顯示鎖堵塞的程度。因此,顏色和高度共同顯示哪些鎖的爭用最激烈。
一個鎖可以擁有很高的豎條但仍然處於綠色。這表示盡管該鎖擁有大量受到堵塞的請求,但總的來說 它擁有很多的成功獲取,因此總堵塞請求的百分比仍然很低。但是,這仍然會影響性能。在圖 9 中的鎖 定柱形圖中,您將看到兩個橙色的豎條:
圖 9. 鎖定柱形圖
在圖 9 中,有兩個鎖值得深入研究,因為兩個豎條都表明激烈的爭用。它們是最高的兩個豎條,這說 明它們擁有最多的受阻請求;它們正在變為紅色,這說明請求那些鎖的受阻請求的總百分比很高。
鎖性能改進策略
帶有非常慢的計數的鎖都可能影響性能。如何減小這些鎖的性能影響?第 一步是檢查哪些代碼正在使用問題鎖。Health Center 顯示鎖的類別,在某些情況下,這足以識別鎖,但 在另一些情況下則無法識別。例如,如果鎖對象的類別是 Object,搜索代碼以引用它可能不太容易。圖 10 展示 Health Center 對鎖行為的分析,涉及 DataStore 類別和 Object 類別的各種鎖。如果 Health Center 將鎖定標識為一個性能問題,但從 Health Center 分析中又不能確定具體是由哪個鎖引起問題, 那麼您可以重構代碼以在鎖對象中使用更明確的類名稱,或者使用一系列 javacore 來捕獲調用最常用鎖 的調用堆棧。
圖 10. 鎖定表
確定問題鎖後,您應該重寫應用程序來減少該鎖的爭用。可以用兩種方法最小化爭用:減少占用鎖的 時間,這將降低沖突發生的幾率;提高使用的鎖對象的數量,這樣每個鎖對象將用於更少的上下文中。
檢查代碼執行
一個方法配置文件將告訴您應用程序正在運行的是哪些代碼。(它並不告訴您應用程序何時等待鎖而 不是運行您的代碼,它也不會告訴您 JVM 何時收集垃圾而不是運行您的代碼)。如果有一個或兩個方法 消耗的 CPU 時間不正常,那麼優化這些方法可以極大地改進性能。圖 11 顯示 Health Center 的 Profiling 透視圖,它包含一個按照活躍程度(熱度)排序的最活躍方法表和一組建議。
圖 11. Profiling 透視圖
如果沒有一個方法的顏色為橙色或紅色,則應用程序的執行在幾個方法之間相對均衡。優化最熱的方 法仍然是值得的,因為它們產生的性能也許還不夠好。例如,某個方法可能過度使用 I/O。在本例中,某 個方法占用的 CPU 資源明顯比其他方法多,因此它的顏色為紅色。通過圖 11 中左邊的 Self 列的值可 以看出,在 JVM 檢查的應用程序的工作時間中,42.1% 的時間用於執行 DataStore.storeData(I) 方法 。右邊的 Tree 列顯示應用程序在 DataStore.storeData(I) 方法及其子方法上花費的時間。在一個簡單 的單線程應用程序中,100% 的 Tree 時間將用於 main() 方法。
代碼優化策略
性能優化的目標是減少應用程序的工作。由於大部分工作發生在方法配置文件中排在前面的方法中, 因此這些方法應該重點考慮。您可以放心地忽略方法配置文件中排在底部的方法。
采樣配置程序和跟蹤配置程序
Health Center 通過每 2 毫秒對調用堆棧進行一次采樣來生成方法配置文件。有些配置程序稱為跟蹤 配置程序,它們跟蹤方法的進入和離開。這提供關於所有被調用方法及其調用時間的詳細信息,但這將為 被配置的應用程序帶來巨大的開銷。Health Center 之所以能夠實現如此低的開銷,方法之一是使用采樣 配置程序替代跟蹤配置程序。但是,由於不知道方法何時開始以及何時結束,采樣配置程序不能區分以下 兩種方法:由於被經常調用而頻繁出現在調用堆棧上的方法;由於需要很長時間才能完成而頻繁出現的方 法。
一個方法出現在方法配置文件頂部的原因有兩個:要麼該方法被頻繁調用,要麼它在被調用時執行的 工作太多。執行帶有循環(特別是嵌套循環)的方法可能需要耗費很多時間。包含多行代碼的方法的執行 時間通常也比代碼行較少的方法的執行時間更長。如果一個只有少量代碼並且不包含循環的方法位於配置 文件的頂部,那麼它可能正被頻繁調用。
有兩種方法可以優化一個應用程序:一是在耗費時間的方法中執行更少的工作,二是減少頻繁調用的 方法的調用次數。要減少方法中執行的工作,最有效的方法是盡量將代碼移出循環。要減少一個方法的調 用次數,方法是找出哪些代碼正在調用該方法,然後取消這些調用。通常,至少是在優化的初始階段,對 配置文件頂部的方法的調用中,相當大的一部分調用都是不必要的,可以安全刪除。在 Health Center 的方法配置文件中選擇一個方法,將在屏幕底部顯示它的調用路徑。圖 12 顯示,對 DataStore.storeData 方法的 90.3% 的調用來自 StoreData.run 方法。
圖 12. 一個調用路徑樹
關注不同的時間間隔
有時,一個應用程序的行為在某個時段內會劇烈變化:垃圾行為變得密集,或者對某個鎖的爭用十分 激烈,或者某個方法迅速躥升至方法配置文件的頂部。 Health Center 支持對某個選定時段進行分析。 用鼠標在柱形圖上拖動一個方框將縮小顯示的時段,這種剪裁將影響所有透視圖。建議將被更新,以只基 於選定的時段。方法配置表也會被更新,以便樣例計數和百分比只針對選定的時段。這允許您,例如,只 看到在 GC 出現問題時執行的方法;或者排除在應用程序啟動期間分析的數據。
示例 2:修復配置問題
在現代環境中,創建和部署一個 Java 應用程序可能需要幾個不同的個人,也可能需要很多大型團隊 ,尤其是當應用程序在一個應用服務器或框架中運行時更是如此。啟動參數可以在幾個不同的位置設置, 要了解哪個 JVM 使用什麼配置運行何種應用程序將非常困難。盡管在正常情況下這完全可以接受,但如 果出現問題,更好地理解 Java 應用程序的配置方式可能非常關鍵。不當的配置可能會導致性能問題,這 些問題並不總是能通過前面介紹過的方法識別,它們會導致異常的應用程序行為並危害服務能力。
Health Center 包含一個名為 Environment 的透視圖,它顯示受監控的應用程序的類路徑、系統屬性 和環境變量。它還分析 Java 配置並提供關於潛在問題的建議。圖 13 顯示 Environment 透視圖:
圖 13. Environment 透視圖
我運行的是哪個 JVM?
在 Environment 透視圖中顯示的最簡單的信息之一是正在被監控的 JVM 的地址。令人驚訝的是,這 個簡單信息通常足以用於解決問題。預期的類不可用嗎?對 JAVA_HOME 中的文件的修改(如日志配置、 安全配置或庫更改)沒有起作用嗎?診斷這些問題時,首要任務是檢查正在運行的 JVM 是不是您所預期 的。大多數現代系統可以安裝許多 JVM,大型應用程序甚至可以在不同的位置包含幾個不同的 JVM。
我正在使用哪些啟動參數運行?
Java 技術支持的命令行選項范圍非常廣泛。某些選項適用特定環境,但不適用其他環境。在一個現代 應用程序部署中,可以在幾個嵌套啟動腳本中設置選項,應用程序實際運行哪些選項並不總是很清楚。 Health Center 提供一個視圖以顯示最終的 Java 命令行,這允許您確定異常的應用程序配置。例如,最 大堆大小可能被限制為較小的值。對於較小的實用應用程序而言,這沒有問題;但對於需要在內存中操作 大型數據集的應用程序而言,這種限制可能會導致崩潰。如果負責這個崩潰的應用程序的團隊不知道這個 最大堆大小設置,他們很難理解為何內存總是不夠用。圖 14 顯示 Health Center 列出一組命令行選項 :
圖 14. 命令行選項清單
Health Center 還能分析可能具有不良後果的 Java 配置和標記選項。例如,在部署的測試階段添加 的選項可能沒有在進入生產階段之前刪除。特別是,幾個調試選項(如 -Xdebug 和 -Xcheck 選項)可能 對於在測試過程中發現問題很方便。但是,這些選項會增加性能開銷,如果要獲得最優性能,應該避免使 用這些選項。其他選項(如 -Xnoclassgc)也許能夠提供一些性能好處,但面臨擴展內存需求不確定的風 險。
我有足夠的信息來診斷應用程序崩潰嗎?
並不是所有的配置問題都與 Java 命令行 相關,有些問題的原因是底層系統屬性。最顯著的因素與 Linux® 和 AIX® 系統對一個進程使用 的資源的限制有關。CPU 使用、消耗的虛擬內存量、文件大小和內核文件大小可以使用 ulimit 命令限制 。盡管這個命令很有用,但它也可能會阻礙問題診斷。如果內核文件因為 ulimit 設置過低而被截短,則 幾乎不可能從它們提取有意義的信息。在某些系統上,默認的 ulimit 設置幾乎總是導致截短內核文件。 (內核文件是進程意外結束時操作系統自動創建的進程映像。對於診斷多種應用程序問題,特別是崩潰問 題,內核文件起到關鍵作用)。
由於內核文件只在問題出現時才生成,因此當找到有問題的 ulimit 設置時通常為時已晚:JVM 已經 崩潰,帶走了診斷問題所需的所有信息。通常,確保 ulimit 不會阻止生成完整的內核文件的惟一方法是 猜測 ulimit 設置可能會出現問題,然後手動檢查 ulimit 設置。遺憾地是,這並不是理想的方法,因為 它涉及相當模糊的知識和大量防御系統管理工作。Health Center 能夠自動探測這種常見的服務能力問題 。使用 Health Center,沒有必要親自檢查 ulimit 設置 — 它將在 ulimit 需要調整時發出一條 警告。
示例 3:評估系統穩定性
盡管在 Java 環境中崩潰並不常見,但 Java 應用程序仍然可能意外終止。這種崩潰有幾個原因。一 個常見原因是:Java 代碼通過 Java Native Interface (JNI) 調用本機代碼,本機代碼中的一個不安全 的內存訪問觸發了一個常規保護錯誤(General Protection Fault,GPF)。另一個常見原因是 Java 應 用程序已經耗盡內存堆,不能繼續執行。Java 應用程序也有可能耗盡本機內存,這也會導致崩潰。由於 內存耗盡(Java 堆或本機內存)而導致的崩潰的特征是一個 OutOfMemoryException。
診斷一個內存漏洞
大多數崩潰都是不可預見的,但某些崩潰則不然。特別是,Health Center 試圖預測由於 Java 堆耗 盡而導致的崩潰。Health Center 不能預測由於企圖實例化一個過大的對象而導致的 OutOfMemoryException,但是大多數 OutOfMemoryException 的原因是內存洩漏:對不再需要的內存的引 用。這個內存不能被垃圾收集器釋放。如果不需要的對象持續增加,最終將沒有空間容納需要的對象,這 時就會出現一個 OutOfMemoryException。圖 15 展示了 Health Center 對一個存在內存洩漏的應用程序 使用的堆的形象化顯示。應用程序的內存需求一直在持續上升,Health Center 發出一條警告,指出最終 可能會導致崩潰。
圖 15. 可疑內存洩漏圖
Heath Center 識別出漏洞後,如何修復漏洞呢?關鍵是要確定哪些對象正在使用洩露的內存。這種分 析最好從一個堆或系統轉儲進行。系統轉儲為堆中的每個對象創建一條記錄,記錄對象使用的內存量,哪 些對象正在引用該對象。持有對不再需要的對象的引用是 Java 應用程序中產生內存洩漏的最普遍原因。
沒有工具支持的話,幾乎不可能執行堆分析,好在我們有一些優秀的工具可用。盡管 Health Center 不分析轉儲,診斷工具家族的另一個成員能夠完成這個工作。與 Health Center 一樣,IBM Monitoring and Diagnostic Tools for Java - Memory Analyzer 可以在 ISA 內免費下載。它提供高級堆內容摘要 ,包括可疑漏洞的識別。通常,這個工具本身就足以確定洩漏原因並修復漏洞。圖 16 展示運行的 Memory Analyzer:
圖 16. ISA 的 Memory Analyzer
對於更復雜的情況,Memory Analyzer 還提供強大的工具以向下鑽取堆內容,其中包括一個對象查詢 語言。
結束語
Health Center 提供范圍廣泛的關於應用程序執行、穩定性和性能的信息。它提供關於 GC 使用的建 議、識別熱方法、突出顯示鎖爭用區域,提供關於應用程序的運行環境的信息。
Health Center 是一個寶貴的開發工具,它能幫助您消除性能問題、內存洩漏和低效代碼,避免問題 出現在生產階段。另外,由於 Health Center 的開銷特別低,它還可以用於解決生產系統上的問題。借 助 Health Center 提供的分析和建議,即使您不是一位 Java 管理和性能調優專家,也能識別和修復問 題。