IBM WebSphere Application Server 診斷和調優---宕機問題分析(一)

IBM WebSphere Application Server 診斷和調優(一)

http://zwchen.iteye.com/blog/646063

大家可以google:“IBM WebSphere Application Server 診斷和調優”。 

近段時間,我們項目中用到的WebSphere應用服務器(WAS),但在客戶的production環境下極不穩定,經常宕機。給客戶造成非常不好的影響,同時,也給項目組很大壓力。爲此,我們花了近一個月時間對其診斷,現在基本上穩定了,需要繼續觀察一段時間。現在我主要將工作做一個階段性的總結。 
我們的產品環境是:WAS6.0+DB2 8.1+AIX5.3+RS/6000。在該產品環境下,出現的問題非常多,現象如下: 
WAS經常不穩定、宕機幾乎一天一次,經常報告OutOfMemory(內存泄漏嗎?NO)。 
DB2連接數過大,有時把DB2撐死,有時也把AIX撐死。 
AIX虛擬內存報錯、分頁報錯、IO也報錯、還有很多其它莫名奇妙的錯。 

總是,每次問題發生的現象和理論上的總是不一致,導致我們不知道從何入手,也無從檢測自己的優化參數。諮詢過多次IBM技術支持,只解決了某些局部問題。 
雖然問題依然存在,但我想,解決問題的思路、特別是理論基礎,還是有一些規律和原則。 

對於WAS這塊,我近段時間的主要時間集中在以下幾個方面(時間順序): 
1、Java性能監測工具:Jprofiler,也用到Jprobe。後來發現Jprofiler在AIX下幾乎不可用。 
2、IBM Java虛擬機和WAS技術細節,特別是IBM JVM的GC原理,我發現它和sun、bea的差別很大。 
3、IBM的heap分析器Heap Analyzer、GCCollector。這兩個事後監測工具非常實用,特別是我們的產品運行環境,非測試環境。 
4、某些Application的懷疑和診斷。 
5、AIX診斷,我幾乎沒有這個能力,只能常規監測一下,需另請高人。 

我打算將本文分成以下幾個部分總結: 
JVM原理、IBM JVM的GC策略和調優 
Jprofiler和IBM工具的實際體會 
WAS的診斷體會和AIX調優 

下面開始主題吧,可能比較零碎,另外,開始的理論篇基本上看書都可以,我只是總結一下,再添加一些自己的理解。 

以下是我參考的最重要的兩本電子書和一些網站: 
《Inside Java Vrtual Machine》:半部分有約四章我認爲非常棒,其它章節可能意義不大。 
《The Java Virtual Machine Specification, 2nd》:前半部分有兩三章很不錯,不過可以對照上一本書看。 
sun的hotspot虛擬機技術:[url]http://java.sun.com/javase/technologies/hotspot/ [/url] 
BEA的JRockit虛擬機技術:[url]http://edocs.bea.com/jrockit/geninfo/genintro/index.html [/url]JVM技術文檔入口,虛擬機理論,內存泄漏診斷等的索引頁。 
IBM診斷資料:http://www-128.ibm.com/developerworks/java/jdk/diagnosis/ 上面有一個500多頁的pdf文檔,對IBM JVM技術和診斷講解很深入。 

我不得不提的是,在查資料這塊,BEA和Sun都有很好的官方文檔和論壇支持,並且官方文檔導航非常好。雖然IBM的診斷資料也不少,但需要搜索,其搜索是很痛苦的。而且,IBM官方論壇很差。如果用IBM的產品出問題,切記:找IBM技術支持,千萬不要蒙着頭搞!反正它們的產品很少免費。說實話,它們的技術支持還是挺負責的,一般會爲你推薦很多support資料,而該資料往往都在developerworks網站上,屬於support那個頻道,但你就是搜不着。 

Java虛擬機規範概要 
研究Java虛擬機,首先要了解Sun的Java虛擬機規範。現在,該實現版本很多,如比較有名的Sun、IBM、BEA、Apple、HP、MS、Apache Harmony。它們都實現了JVM規範,但有各自擴展。譬如,針對IBM虛擬機的堆碎片導致OutOfMemory(OOM),在Sun的虛擬機上就不會發生。Sun的JVM有maxPermSize的概念,IBM就沒有,如果你設置這個參數,虛擬機根本就啓動不了。 
比較有意思的是,學Java,就一定要了解各種規範,這和MS的風格很不一樣。Sun總是在定義一些規範,實現都留給各廠商。我們除了理解規範本身外,一定要理解規範和實現之間的關係,譬如JDBC規範和JDBC驅動的關係,它們是怎麼組合到一起的。要是你用過php的xml解析庫,或db函數,就會體會深刻,它們可沒有什麼規範可言,所以每個數據庫廠商的db函數用法都不一樣。我推薦大家研讀一下HSQLDB的jdbc和Tomcat的servlet相關實現,因爲我認爲它們還是比較好懂的。 
JVM規範只是定義一個虛擬機該做什麼,但它並沒有要求你該怎麼做。例如我們最常見的Servlet規範,在該規範中,有HttpServletRequest、HttpServletResponse,HttpSession等接口,但它們的實現都留給了各個容器廠商。遺憾的是,規範留下的空白,會把我們這些開發人員給整慘了:容器間移植有時候就是惡夢。譬如J2EE並沒有SSO規範,但它很重要,我以前專門針對它做過WebSphere AppServer和Weblogic AppServer的SSO項目,差別還是不小,不過還是有點共通,那就是都遵循JAAS規範。 

JVM的結構 
從功能上分,Java虛擬機主要由六個部分組成,可以分成三類: 
第一類:JVM API:就是我們最常用的Java API,它是開發人員和Java交互的入口,它主要是JAVA_HOME/jre/lib下的運行時類庫rt.jar和編譯相關的tools.jar 

第二類:JVM內部組件 
類裝載器(ClassLoader):將Byte Array的 .class文件裝載、鏈接和初始化。 
內存管理(Memory Managent):爲對象分配內存,以及釋放內存。後者就是垃圾回收Garbage Collector(GC)。由於JVM最複雜的、最影響性能的就是GC,所以內存管理一般就指垃圾回收。 
診斷接口(Diagostics Interface):這主要體現在JVMTI(jdk1.4下的JVMPI和JVMDI),它主要用來診斷程序的問題和性能,一般提供給工具廠商實現。如eclispe IDE下的debug功能,Jprofiler性能調優工具。 
類解釋器(Interpreter):解釋裝載進虛擬機的class對象,包括JIT等特性相關。 

第三類:平臺相關接口(Platform Interface):主要爲了跨操作系統平臺重用JVM代碼,不過,它和我們開發人員關係不大。 
在以上六個組件中,我們開發人員最關心的是ClassLoader和GC,用Java做系統框架、容器和它們密切相關。做業務系統時一些基礎代碼也和它們打交道,譬如最常用的Class.forName(),Thread.currentThread.getContextClassLoader()。我們仔細想想,爲什麼是上面兩個問題?因爲,它和我們class的整個生命週期最爲相關:怎麼將一個class和相關class加載進來,class實例什麼時候創建,什麼時候被銷燬? 
所以,下面的部分我們要專門討論這些問題。 

ClassLoader 
JVM主要有三類ClassLoader:Bootstrap、Extention、Application,該三類ClassLoader從上到下是分級(hierarchy)結構,遵循代理模型(Delegation Model)。 
Tip:大家可以看看sun.misc.Launcher的源碼,Bootstrap和Extention就在該文件裏。該src可以在sun的網站上下載該壓縮包,約60M(jdk-1_5_0-src-scsl.zip),它不在jdk自帶的那個src.zip裏。 

Bootstrap ClassLoader:也稱爲primordial(root) class loader。主要是負責裝載jre/lib下的jar文件,當然,你也可以通過-Xbootclasspath參數定義。該ClassLoader不能被Java代碼實例化,因爲它是JVM本身的一部分。 

Extention ClassLoader:該ClassLoader是Bootstrap classLoader的子class loader。它主要負責加載jre/lib/ext/下的所有jar文件。只要jar包放置這個位置,就會被虛擬機加載。一個常見的、類似的問題是,你將mysql的低版本驅動不小心放置在這兒,但你的Web應用程序的lib下有一個新的jdbc驅動,但怎麼都報錯,譬如不支持JDBC2.0的DataSource,這時你就要當心你的新jdbc可能並沒有被加載。這就是ClassLoader的delegate現象。常見的有log4j、common-log、dbcp會出現問題,因爲它們很容易被人塞到這個ext目錄,或是Tomcat下的common/lib目錄。 

Application ClassLoader:也稱爲System ClassLoaer。它負責加載CLASSPATH環境變量下的classes。缺省情況下,它是用戶創建的任何ClassLoader的父ClassLoader,我們創建的standalone應用的main class缺省情況下也是由它加載(通過Thread.currentThread().getContextClassLoader()查看)。 
我們實際開發中,用ClassLoader更多時候是用其加載classpath下的資源,特別是配置文件,如ClassLoader.getResource(),比FileInputStream直接。 

ClassLoader是一種分級(hierarchy)的代理(delegation)模型。 
Delegation:其實是Parent Delegation,當需要加載一個class時,當前線程的ClassLoader首先會將請求代理到其父classLoader,遞歸向上,如果該class已經被父classLoader加載,那麼直接拿來用,譬如典型的ArrayList,它最終由Bootstrap ClassLoader加載。並且,每個ClassLoader只有一個父ClassLoader。 
Class查找的位置和順序依次是:Cache、parent、self。 
Hierarchy:上面的delegation已經暗示了一種分級結構,同時它也說明:一個ClassLoader只能看到被它自己加載的classes,或是看到其父(parent) ClassLoader或祖先(ancestor) ClassLoader加載的Classes。 
在一個單虛擬機環境下,標識一個類有兩個因素:class的全路徑名、該類的ClassLoader。 

我碰到的一個典型的例子是:在做WAS的SSO開發時,由於我們的類是由WAS在啓動時加載,該ClassLoader比下面的部署的Applicaton的ClassLoader的級別高。所以,在我們自己的類中沒法用到應用程序的連接池,必須自建。 
代理模型是Java安全模型的保證。譬如,我們自己寫一個String.java,並且編譯、package到自己的java.lang包下。按照代理模型,當前線程的ClassLoader會將其代理到父ClassLoader,父ClassLoader(最終會是Bootstrap)會找到rt.jar下的String.class,也就是說我們的String.class不會搗亂。 

自定義ClassLoader 
我們前面說過,自定義ClassLoader的缺省父ClassLoader是Application ClassLoader。一般的應用開發用不到它,但我們最好理解。因爲在內存泄漏查找、應用程序部署出問題時,很多都和它有關。 
譬如,內存泄漏是怎麼產生的?這就涉及到ClassLoader和Class的生命週期。我曾經碰到這樣一個問題:我們的程序用到了Webwork和Spring框架,當部署到Tomcat下時沒有任何問題,但部署到WAS下,報告找不到Webwork的xml的DTD文件,而且Spring的日誌也總是失效。Why?因爲解析xml dtd時,用的是IBM的Xerces,不是我們的。而Spring日誌問題是因爲應用程序用的是WAS的Common-log.jar,而不是我們的。將應用的ClassLoader從默認的Parent-First,改成Parent-Last就可以解決,不過我們項目中用到其它庫,又發生了其它問題。 

一般來說,用到自定義ClassLoader有三種情況: 
1、應用框架可以自己控制Classes的目錄,並且自動部署。 
我讀過Jive公司的Wildfire(著名的即時通訊服務器),它自己有一套應用框架,非常靈活,遵循該框架插件規範的的第三方的plug-in放置在指定目錄可以自動部署,實現某些擴展功能,如文件傳輸、語音聊天。 
2、區分用戶代碼 
這被廣泛應用在Servlet容器和類似容器,譬如EJB Container設計中,大家看到Tomcat下有common、server、share三個目錄吧(ClassLoader順序從左到有),另外也有用戶應用的WEB-INF目錄,它是我們自己開發的。 
3、允許Classes卸載 
如果沒有自定義的ClassLoader,那麼我們自己應用中的classes永遠都不能被卸載,因爲這些類被Application ClassLoader加載後cache起來了,我們的classes一直對該ClassLoader有引用,而該系統級的ClassLoader永遠都不會被卸載,除非JVM shutdown了。JSP和Servlet的動態部署就用到這個特性。 
待續……. 

Note: 還有JVM運行時(Runtime)架構,ClassLoader加載class過程沒有總結,這兩部分我覺得太重要了,但內容太多,寫不完啊。 
這部分內容,《Inside Java Virtual Machine》講解非常清楚,BEA的官方網站這部分也非常不錯,要理解深刻,我建議結合JProfiler工具,非常直觀。 

待續……. 

該文僅存的一點回復: 
[zwchen] 
爲什麼都說WAS難用? 

安裝過程 
1、先安裝WAS,然後創建三種不同類型的profiles(manager,default,custom),譬如缺省的profiles吧,在創建這個profiles過程中,需要啓動至少10個端口,要是那10個默認端口有些被你的系統佔用了,麻煩就來了。改端口不就ok了嗎?但你知道怎麼改嗎?可能你覺得沒有必要10個端口,但WAS就是需要這麼多:控制檯端口兩個(http,https),引導端口2089,soap、ORB,單元 cell發現….  總之,你都不知道你爲什麼要關心這麼多端口。WLS夠絕了:一個smart端口 7001全部搞定,在上走各種協議。 
2、系統爲你生成的上百個bat命令文件,裏面交叉引用的path都是絕對路徑,所以,往往你的機器重裝了,那麼WAS也重裝吧。WLS和JBoss可以將整個文件夾移動,WAS不行,如果你喜歡折騰,當然也可以做到,就看值不值了。 
控制檯的部署過程 
1、它總是以爲我們的應用前臺是httpd Server分發,於是讓我們選擇虛擬主機。其實,我們不是CMS系統,我們的Web前端就是WAS的web容器。 
2、它總是以爲我們的應用包含EJB,或是要發佈成Web Services,於是讓我們選擇進退兩難。其實,我們只是簡單的Web應用。 
3、它總是以爲我們的應用要部署分散在多個WAS上,或者在cluster裏,所以會強制要求我們選擇發佈目標位置。其實,我們只是用單Server。 
4、它以爲我們發佈的應用是EAR企業包,而WAR包只是一個Web前端展示模塊,所以它總是在xml配置裏面寫一堆。其實,我們很想手動修改配置文件。 
我剛纔特別部署了一個簡單的web應用,就是Struts的sample,寫入了29個xml配置文件。設想,保存部署文件是一個事務性的過程,如果你在大連,服務器在北京,速度超級慢,這個寫入文件過程失敗,呵呵,你就下地獄吧,我們碰到個幾次,有一次就被迫服務器profiles重建。 
雖然上面很多步驟我省略了,對於我特別說到的,雖然有默認,但每個默認頁有上10個選項,而你並不是很明白這些選擇的確切含義,它們是否相互衝突。 
我建議WAS的設計師:請留下儘量少的發佈步驟,需要定製,可以部署後修改,學學WLS吧:考慮普通開發人員的感受。 

開發過程 
用WAS,最好有其配套的開發工具,eclipse那個WAS插件,我試過不太好用。用RAD吧,要lisence。RAD也是個超級大戶,官方推薦內存是最低768M,WAS官方推薦大概是1000M,我的1G機器也可以跑,就是慢了點。 

大家如果用WAS的EJB容器,並且你想做standalone的ejb客戶端,那麼,千萬不要選擇IBM之外的JVM,我固執地試過,最後用sun的JVM成功了,但需要一堆IBM WAS下的jar,而且必須走IIOP協議,我可以說,初次使用99%的嘗試是失敗的。而且,此時的開發工具一定要選擇IBM的 RAD或WSAD。建議,學習EJB這類分佈式開發階段,用WLS或JBoss吧,因爲它們的EJB standalone客戶端都支持smart stub。譬如,對於JBoss,它會通過socket先將客戶端stub下載到本地,你察覺不到這個過程。大概WLS是通過反射生成stub。而WAS 必須部署過程編譯一堆stub,需要引用一堆jar,sun的ejb部署大概也這樣。之所以sun的簡單點,那是因爲你的ejb客戶端jar往往自動被它加入了classpath,或者客戶端是在AppServer裏。 

如果你要開發基於WAS的Web Services,並且用WAS內置的Web Services引擎,那麼你一定要用它自己的開發工具發佈和部署,我雖然成功了,只是因爲太固執,付出的代價太大。 

問題診斷 
用WAS出問題比不出問題正常。出問題咋辦?這個我暫時不說了,留給我的後文吧,總之一句話:問題獨一無二。 

我本人並不是說WAS做得爛,我只是想說明一點,它的使用,對我們的理論技術水平要求太高,特別不適合初學者。 

———————————————————- 
拋出異常的愛 寫道 
用的是5.只有一本。。。中文的。。 
6有沒有中文的紅寶書? 

[zwchen]像是現在還沒有,我建議看它的原著吧,非常易懂,圖特多,一天看200多頁應該不困難。學習WAS,往往一本紅皮書是不夠的。市面上介紹WAS的書,大概極少有超越紅皮書的。 

——————————————————– 

[zwchen]慚愧啊,我確實算不上高手,真正的高手在北京的IBM中國技術支持中心。我和那邊的人電話和郵件聊過好多次,那纔是一個字:高! 
瞭解WAS,我隨便總結一下吧: 

引用

前提:你是項目組專門負責WAS上開發、部署、調優的,並且有與WAS抗爭的決心。 
1、學習WAS寶典叢書:WAS相關紅皮書,前面我介紹過幾本。並且多研究研究WAS的目錄結構。 
2、一本非紅皮書,IBM內部的技術支持彙總,主要是關於診斷,但它最難吃透但最受用:《IBM Developer Kit and Runtime Environment, Java 2 Technology Edition, Version 6.0  Diagnostics Guide》,500多頁。
3、一定要有JVM相關技術積累:ClassLoader、GC策略,而且一定要注意它們與Sun的JVM的區別,往往WAS的問題發生在這個上面。如Sun的JVM一般建議heap的最大最小值一樣,但IBM的JVM你要是這麼做會導致嚴重的碎片問題。Why?默認的GC策略不同。 
4、用JProfiler這類工具深入到WAS內部。 
5、最好對JavaEE相關技術的原理有較深入的瞭解,譬如EJB的原理、Servlet的原理。而且,最好是這些技術怎麼實現的,譬如讀讀Tomcat的源碼,我強烈建議大家讀一下這篇文章:http://www.onjava.com/pub/a/onjava/2003/05/14 /java_webserver.html。



整體體會,WAS的功底是在WAS之外,它只是對JVM、JavaEE規範的一個實現罷了。 
另外也建議:不要花太多的時間的在WAS上,我認爲非常不值。想研究,還不如去看JBoss,WLS。WAS這東西,知道一般的用法就夠了,而且你永遠都不可能明白它爲什麼有那麼多的bug和不合理,明白了又能咋樣?你的時間都白白浪費了。 


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