WebSphere的類載入和故障排查

CloudSpace發表於2009-11-04

上次在WebSphere的類載入機制和故障排查一文中整理了一下Classloader的一些概念和載入原理,但是概念的應用不是很明確,故障排查也沒有具體的方法。所以今天再次整理了IBM developerworks裡有參考價值的文章,希望在遇到ClassCastException、ClassNotFoundException、NoClassDefFoundException、UnsatisfiedLinkError的錯誤時提供解決思路。

IBM WebSphere 開發技術期刊: 類路徑衝突的鑑別》一文描述了應用遷移過程中所發生的“故障”,打引號那是因為WAS並沒有發出ClassNotFoundException、NoClassDefFoundException等的錯誤資訊,而是“並非預期中的表現”。最終排查的結果是:

其結果是C:/Program Files/IBM/WebSphere Studio/Application Developer/v5.1.1/runtimes/base_v51/lib/jython.jar,而不是我們期望的WEB-INF/lib/jakarta-oro-2.0.7.jar

這是一個很典型的類載入錯誤例子,預設的PARENT_FIRST載入模式讓類載入器從應用程式類裝入器中先載入了jython.jar(正好有需要的同名類),而不是Web 模組類裝入器里正確的jakarta-oro-2.0.7.jar。解決的方法可以啟用PARENT_LAST 載入模式即可。文章中檢測類載入路徑的Servelet可以作為參考,不過我覺得一般會用-verbose命令列選項開啟 IBM JVM 的詳細輸出、trace某個確定類的情況或者dump的方法找到類載入路徑。

除錯方法

《類裝入問題解密,第 1 部分: 類裝入和除錯工具介紹》介紹了這三種方法

可以用-verbose命令列選項開啟 IBM JVM 的詳細輸出。當某些事件發生的時候(例如,類裝入時),詳細輸出會在控制檯上顯示資訊。要想得到額外的類裝入資訊,可以用詳細類輸出。可以用-verbose:class選項啟動這個模式。

解釋詳細輸出
詳細輸出列出已經開啟的所有 JAR 檔案,包括到這些 JAR 的完整路徑。下面是一個示例:

...
[Opened D:\jre\lib\core.jar in 10 ms]
[Opened D:\jre\lib\graphics.jar in 10 ms]
...

所有裝入的類都已經列出,同時還指出它們是從哪個 JAR 檔案或目錄裝入的。例如:

...
[Loaded java.lang.NoClassDefFoundError from D:\jre\lib\core.jar]
[Loaded java.lang.Class from D:\jre\lib\core.jar]
[Loaded java.lang.Object from D:\jre\lib\core.jar]
...

可以僅輸出某個特定的類載入情況,剔除無關緊要的類:

-Dibm.cl.verbose=。可以用正規表示式宣告類的名稱,例如Hello*會跟蹤所有以Hello開頭的名稱。

更準確的就是用trace工具來跟蹤java程式碼

IBM JVM 有一個內建的方法跟蹤工具。這樣,不需要修改 Java 程式碼,就可以跟蹤任何 Java 程式碼(包括核心系統)中的方法。因為這個工具可以提供大量資料,所以可以控制跟蹤的級別,只獲取需要的資訊。

比較常用的步驟是

  1. 在控制檯導航樹中單擊故障診斷 > 記錄和跟蹤,然後單擊服務 > 診斷跟蹤
  2. 單擊配置
  3. 選中啟用記錄核取方塊啟用跟蹤,清除此核取方塊禁用跟蹤。

…………

    1. 在控制檯導航樹中單擊故障診斷 > 記錄和跟蹤
    2. 選擇伺服器名。
    3. 單擊更改日誌級別詳細資訊
    4. 如果已啟用所有元件,那麼可能要關閉它,然後啟用特定元件。
    5. 單擊元件或組名。要獲取更多詳細資訊,請參閱日誌級別設定。 如果所選伺服器未在執行,您將無法以圖形方式檢視個人元件。
    6. 在跟蹤字串框中輸入跟蹤字串。
    7. 選擇應用,然後選擇確定

    要輸入跟蹤字串以將跟蹤規範設定為需要的狀態:

亦可以在故障診斷 > 類裝入器檢視器 以訪問企業應用程式拓撲頁

在“類裝入器檢視器”頁中,單擊搜尋以訪問搜尋頁,在該頁面上,可以在類裝入器中搜尋下列內容:

  • 特定字串
  • 特定 .jar 檔案
  • 特定目錄中的檔名
  • 特定類裝入器裝入的檔名

搜尋區分大小寫

用Trace來跟蹤應用程式情況其實是很有技術含量的活,能自成一章。我接觸的專案基本到了這一層都是由開發人員去找BUG,所以實踐比較少,沒有分享的心得。有機會的話我以後學習學習再寫。

如果你覺得用trace來跟蹤除錯比較複雜,那麼可以直接生成一個javacore檔案,裡面會記錄類裝入器資訊。推薦用wsadmin命令來生成core檔案,因為kill -3帶出個heapdump可就不好玩了。

鍵入wsadmin.bat命令,進入wsadmin管理命令列,鍵入如下程式碼:

set jvm [$AdminControl completeObjectName type=JVM,process=server1,*]
$AdminControl invoke $jvm dumpThreads

javacore.TIMESTAMP.NUMBER.txt  檔案會自動在C:\WebSphere\AppServer或C:\WebSphere\AppServer\default\或您指定的目錄中產生。

解決問題

瞭解了查詢的方法,那麼就可以開始解決問題:《類裝入問題解密,第 2 部分: 基本的類裝入異常

ClassNotFoundException是最常見的類裝入異常型別。它發生在裝入階段。Java 規範對ClassNotFoundException的描述是這樣的:

當應用程式試圖通過類的字串名稱,使用以下三種方法裝入類,但卻找不到指定名稱的類定義時丟擲該異常。

  • Class中的forName()方法。
  • ClassLoader中的findSystemClass()方法。
  • ClassLoader中的loadClass()方法。

所以,如果顯式地裝入類的嘗試失敗,那麼就丟擲ClassNotFoundException

通過丟擲ClassNotFoundException,類裝入器提示,定義類時所需要的位元組碼在類裝入器所查詢的位置上不存在。這些異常修復起來通常比較簡單。可以用 IBM 的 verbose 選項檢查類路徑,確保使用的類路徑設定正確。如果類路徑設定正確,但是仍然看到這個錯誤,那麼就是需要的類在類路徑中不存在。要修復這個問題,可以把類移動到類路徑中指定的目錄或 JAR 檔案中,或者把類所在的位置新增到類路徑中

 

個人感想

類載入問題是一個不難解決卻又令人頭疼的問題,特別當多個應用部署在一起的時候。問題狀況相似,其實出錯的原因並不相同,往往單獨成功的例子——例如jar包換個目錄,對於另一個環境卻束手無策。網上有不少的“解決案例”就是這種情況,所以我把“漁”的方法整理在這裡,並非個人原創,都是照搬IBM developerworks已有的內容。慚愧之餘,也感嘆一下IBM的強大。其它的大型廠商,Oracle是需要Metelink帳號才能看到最有用的資料;SAP也需要購買產品後才能檢視詳細文件,否則就是簡陋兩字;Microsoft的KB和webcasting做的很好,但是本地化和有價值的文章卻遜一籌。在都想依靠服務賺錢的現在,IBM沒有把這些資料敝帚自珍,讓我們有個學習交流的環境,這也許是它數十年它經久不衰的奧祕之一吧。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14789789/viewspace-618079/,如需轉載,請註明出處,否則將追究法律責任。

相關文章