szhswl
          宋針還的個人空間
            要獲得更好的性能,就需要對原來的系統(tǒng)進(jìn)行性能調(diào)優(yōu)。對運行在Glassfish上的JavaEE應(yīng)用,調(diào)優(yōu)是一件相對復(fù)雜的事情。在調(diào)優(yōu)以前必須要認(rèn)識到:對JavaEE的系統(tǒng),調(diào)優(yōu)是多層次的。一個JavaEE的應(yīng)用其實是整個系統(tǒng)中很少的一部分。開發(fā)人員所開發(fā)的JavaEE程序,無論是JSP還是EJB,都是運行在JavaEE應(yīng)用服務(wù)器(Glassfish)之上。而應(yīng)用服務(wù)器本身也是Java語言編寫的,需要運行在Java虛擬機之上。Java虛擬機也只不過是操作系統(tǒng)的一個應(yīng)用而已,和其他的應(yīng)用(如Apache)對于操作系統(tǒng)來說沒有本質(zhì)的區(qū)別。而操作系統(tǒng)卻運行在一定的硬件環(huán)境中,包括CPU,內(nèi)存,網(wǎng)卡和硬盤等等。在這么多的層次中,每一個層次的因素都會影響整個系統(tǒng)的性能。因此,對一個系統(tǒng)的調(diào)優(yōu),事實上需要同時對每個層次都要調(diào)優(yōu)。JavaEE應(yīng)用性能調(diào)優(yōu)不僅僅和Glassfish有關(guān),Java語言有關(guān),還要和操作系統(tǒng)以及硬件都有關(guān)系,需要調(diào)優(yōu)者有綜合的知識和技能。這些不同層面的方法需要綜合縱效,結(jié)合在一起靈活使用,才能快速有效的定位性能瓶頸。下面是一些具體的案例分析:

           

          內(nèi)存泄漏問題

                  某個JavaEE應(yīng)用運行在8顆CPU的服務(wù)器上。上線運行發(fā)現(xiàn)性能不穩(wěn)定。性能隨著時間的增加而越來越慢。通過操作系統(tǒng)的工具(mpstat),發(fā)現(xiàn)在系統(tǒng)很慢的時候,只有一顆CPU很忙,其他的CPU都很空閑。因此懷疑是Java虛擬機經(jīng)常進(jìn)行內(nèi)存回收,因為虛擬機在內(nèi)存回收的時候,有的回收算法通常只能運行在一個CPU上。通過Java虛擬機的工具“jstat”可以清楚的看到,Java虛擬機進(jìn)行內(nèi)存回收的頻率非常高,幾乎每5秒中就有一次,每次回收的時間為2秒鐘。另外,通過“jstat”的輸出還發(fā)現(xiàn)每次回收釋放的內(nèi)存非常有限,大多數(shù)對象都無法回收。這種現(xiàn)象很大程度上暗示著內(nèi)存泄漏。使用Java虛擬機的工具“jmap”來獲得當(dāng)前的一個內(nèi)存映象。發(fā)現(xiàn)有很多(超過10000)個的session對象。這是不正常的一個現(xiàn)象。一般來說,session對應(yīng)于一個用戶的多次訪問,當(dāng)用戶退出的時候,session就應(yīng)該失效,對象應(yīng)該被回收。當(dāng)我們和這個系統(tǒng)的開發(fā)工程師了解有關(guān)session的設(shè)置,發(fā)現(xiàn)當(dāng)他們部署應(yīng)用的時候,竟然將session的timeout時間設(shè)置為50分鐘,并且沒有提供logout的接口。這樣的設(shè)置下,每個session的數(shù)據(jù)都會保存50分鐘才會被回收。根據(jù)我們的建議,系統(tǒng)提供了logout的鏈接,并且告訴用戶如果退出應(yīng)用,應(yīng)該點擊這個logout的鏈接;并且將session的timeout時間修改為5分鐘。通過幾天的測試,證明泄漏的問題得到解決。

           

          數(shù)據(jù)庫連接池問題

                  某財務(wù)應(yīng)用運行在JavaEE服務(wù)器上,后臺連接Oracle數(shù)據(jù)庫。并發(fā)用戶數(shù)量超過100人左右的時候系統(tǒng)停止響應(yīng)。通過操作系統(tǒng)層面的進(jìn)程監(jiān)控工具發(fā)現(xiàn)進(jìn)程并沒有被殺死或掛起,而CPU使用率幾乎為零。那么是什么原因?qū)е孪到y(tǒng)停止響應(yīng)用戶請求呢?我們利用Java虛擬機的工具(kill -3 pid)將當(dāng)前的所有線程狀態(tài)DUMP出來,發(fā)現(xiàn)JavaEE服務(wù)器的大部分處理線程都在等待數(shù)據(jù)庫連接池的連接,而那些已經(jīng)獲得數(shù)據(jù)庫連接的線程卻處于阻塞狀態(tài)。數(shù)據(jù)庫管理員應(yīng)要求檢查了數(shù)據(jù)庫的狀態(tài),發(fā)現(xiàn)所有的連接的session都處于死鎖狀態(tài)。顯然,這是因為數(shù)據(jù)庫端出現(xiàn)了死鎖的操作,阻塞了那些有數(shù)據(jù)庫操作的請求,占用了所有數(shù)據(jù)庫連接池中的連接。后續(xù)的請求如果還要從連接池中獲取連接,就會阻塞在連接池上。當(dāng)解決數(shù)據(jù)庫死鎖的問題之后,性能問題迎刃而解。

           

          大對象緩存問題

                  電信應(yīng)用運行在64位Java虛擬機上,系統(tǒng)運行得很不穩(wěn)定,系統(tǒng)經(jīng)常停止響應(yīng)。使用進(jìn)程工具查看,發(fā)現(xiàn)進(jìn)程并沒有被殺死或掛起。利用Java虛擬機的工具發(fā)現(xiàn)系統(tǒng)在長時間的進(jìn)行內(nèi)存回收,內(nèi)存回收的時間長達(dá)15分鐘,整個系統(tǒng)在內(nèi)存回收的時候就像掛起一樣。另外還觀察到系統(tǒng)使用了12G的內(nèi)存(因為是64位虛擬機所以突破了4G內(nèi)存的限制)。從開發(fā)人員那里了解到,這個應(yīng)用為了提高性能,大量使用了對象緩存,但是事與愿違,在Java中使用過多的內(nèi)存,雖然在正常運行的時候能夠獲得很好的性能,但是會大大增加內(nèi)存回收的時間。特別是對象緩存,本系統(tǒng)使用了8G的緩存空間,共緩存了6000多萬個對象,對這些對象的遍歷導(dǎo)致了長時間的內(nèi)存回收。根據(jù)我們的建議,將緩存空間減少到1G,并調(diào)整回收算法(使用增量回收的算法),使得系統(tǒng)由于內(nèi)存回收而造成的最大停頓時間減少到4秒,基本滿足用戶的需求。


          外部命令問題

                  數(shù)字校園應(yīng)用運行在4CPU的Solaris10服務(wù)器上,中間件為JavaEE服務(wù)器。系統(tǒng)在做大并發(fā)壓力測試的時候,請求響應(yīng)時間比較慢,通過操作系統(tǒng)的工具(mpstat)發(fā)現(xiàn)CPU使用率比較高。并且系統(tǒng)占用絕大多數(shù)的CPU資源而不是應(yīng)用本身。這是個不正常的現(xiàn)象,通常情況下用戶應(yīng)用的CPU占用率應(yīng)該占主要地位,才能說明系統(tǒng)是正常工作。通過Solaris 10的Dtrace腳本,我們查看當(dāng)前情況下哪些系統(tǒng)調(diào)用花費了最多的CPU資源,竟然發(fā)現(xiàn)最花費CPU的系統(tǒng)調(diào)用是“fork”。眾所周知,“fork”系統(tǒng)調(diào)用是用來產(chǎn)生新的進(jìn)程,在Java虛擬機中只有線程的概念,絕不會有進(jìn)程的產(chǎn)生。這是個非常異常的現(xiàn)象。通過本系統(tǒng)的開發(fā)人員,我們找到了答案:每個用戶請求的處理都包含執(zhí)行一個外部shell腳本,來獲得系統(tǒng)的一些信息。這是通過Java的“Runtime.getRuntime().exec”來完成的,但是這種方法在Java中非常消耗資源。Java虛擬機執(zhí)行這個命令的方式是:首先克隆一個和當(dāng)前虛擬機一樣的進(jìn)程,再用這個新的進(jìn)程去執(zhí)行外部命令,最后再退出這個進(jìn)程。如果頻繁執(zhí)行這個操作,系統(tǒng)的消耗會很大,不僅在CPU,內(nèi)存操作也很重。用戶根據(jù)建議去掉這個shell腳本執(zhí)行的語句,系統(tǒng)立刻回復(fù)了正常。

           


          文件操作問題

                  內(nèi)容管理(CMS)系統(tǒng)運行在JavaEE服務(wù)器上,當(dāng)系統(tǒng)長時間運行以后,性能非常差,用戶請求的延時比系統(tǒng)剛上線的時候要大很多,并且用戶的并發(fā)量很小,甚至是單個用戶也很慢。通過操作系統(tǒng)的工具觀察,一切都很正常,CPU利用率不高,IO也不是很大,內(nèi)存很富余,網(wǎng)絡(luò)幾乎沒有壓力(因為并發(fā)用戶少)。先不考慮線程互鎖的問題,因為單個用戶性能也不好。通過Java虛擬機觀察也沒有發(fā)現(xiàn)什么問題(內(nèi)存回收很少發(fā)生)。這使得我們不得不使用代碼跟蹤器來全程跟蹤代碼。我們采用了Netbeans的Profiler,跟蹤的結(jié)果非常意外,用戶請求的90%的時間在創(chuàng)建新文件。從系統(tǒng)設(shè)計人員了解到,此系統(tǒng)使用了一個目錄用于保存所有上傳和共享的文件,文件用其命名方式來唯一區(qū)別于其他文件。我們查看了那個文件目錄,發(fā)現(xiàn)該目錄下已經(jīng)擁有80萬個文件了。這時候我們才定位到問題了:在同個目錄下放置太多的文件,在創(chuàng)建新文件的時候,系統(tǒng)的開銷是比較大的,例如為了防止重名,文件系統(tǒng)會遍歷當(dāng)前目錄下所有的文件名等等。根據(jù)我們的建議,將文件分類保存在不同的目錄下,性能有了大幅度的提高。

           


          高速緩存命中率問題

                  運行在JavaEE服務(wù)器上的ERP系統(tǒng),在CPU充分利用的情況下性能仍然不太好。從操作系統(tǒng)層面上觀察不到什么大問題,而且ERP系統(tǒng)過于復(fù)雜,代碼跟蹤比較困難。于是進(jìn)行了CPU狀態(tài)的進(jìn)一步檢查,發(fā)現(xiàn)CPU的TLB命中率不是很高,于是對Java虛擬機的啟動參數(shù)進(jìn)行了修改,強迫虛擬機使用大尺寸的內(nèi)存頁面,提高TLB的命中率。下面的參數(shù)是在Sun的HOTSPOT中調(diào)整大尺寸(4M)頁面的設(shè)置:
          -XX:+AggressiveHeap
          -XX:LargePageSizeInBytes=256m
          通過調(diào)整,TLB命中明顯提高,性能也得到近40%的提升。

          轉(zhuǎn)自:http://developers.sun.com.cn/blog/yutoujava/entry/8



          ---------------------------------------------------------------------------------------------------------------------------------
          說人之短,乃護(hù)己之短。夸己之長,乃忌人之長。皆由存心不厚,識量太狹耳。能去此弊,可以進(jìn)德,可以遠(yuǎn)怨。
          http://www.aygfsteel.com/szhswl
          ------------------------------------------------------------------------------------------------------ ----------------- ---------
          posted on 2008-07-12 22:06 宋針還 閱讀(230) 評論(0)  編輯  收藏 所屬分類: 常見問題

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 竹溪县| 济南市| 思南县| 寿阳县| 苍梧县| 修文县| 故城县| 太湖县| 崇州市| 北海市| 田林县| 五莲县| 铁岭市| 临洮县| 襄城县| 宁城县| 隆子县| 辽宁省| 体育| 上思县| 太谷县| 沅江市| 读书| 福州市| 呼图壁县| 景德镇市| 拉孜县| 阿拉尔市| 星子县| 桃园市| 淄博市| 临颍县| 武胜县| 定西市| 隆子县| 万宁市| 昆明市| 宁远县| 延寿县| 辽中县| 墨竹工卡县|