優化 Java 垃圾收集器改進系統性能
|
|
級別: 高級
李 曉華
(xiaohual@cn.ibm.com), IBM CDL ODSC部門工程師
2006 年 11 月 30 日
在系統的性能測試過程中,當系統的處理能力有某種變化趨勢時, 除了關于等待隊列、執行線程,EJB 池以及數據庫連接池和 Statement Cache 方面的調優外,還要考慮到 Java 垃圾收集器(Garbage Collection,本文簡稱 GC)對系統性能的影響。本文介紹了如何分析系統的處理能力和 GC 之間的關系,以及如何通過改進 JVM 的配置來優化 GC,以提高系統的性能。
項目背景
某個大型項目的 CPU100% 的壓力性能測試, 用以檢查在系統運行環境不正常的情況下,系統可以運行到何種程度。測試過程是: 請求測試的模擬器向系統不斷發出大量請求, 系統接受由模擬器發出的請求,然后將請求置于一個任務池中,如果當前有空閑的線程,則該線程會從任務池中取出一個任務進行處理,如果沒有空閑的線程,則該任務一直會待在任務池中,直到有空閑的線程來處理它。因此,任務池的隊列的長度從某種意義上可以代表整個系統的處理能力,任務池隊列的長度用 Q 值來表示,如果 Q 值超出了一定限額,將會有流量控制的線程將超出限額的待處理任務丟棄,以保證系統的穩定性。
整個測試要求得到系統所在服務器的負載達到將近 100% 時,系統的吞吐量,相應時間以及在超負荷下業務請求成功率。
問題現象描述
在測試過程中,任務池中累積的任務數起伏很大,正常時累積的任務數很小,但是每隔一段時間會累積大量的任務。由于累積的任務數超出任務池流量控制所定義的限額,所以每隔一段時間,大量的待處理任務被清除。因此測試結束后得到的在超負荷下業務請求成功率也不是很理想。
應用服務器的物理部署
一臺AIX服務器(4CPU,4GMemory)來部署本Web應用程序;Web應用程序部署在中間件應用服務器上;部署了一個節點(Node),只配置一個應用服務器實例(Instance),沒有做Cluster部署。
分析
檢測WebSphere Application Server上的Web Container,EJB Container , ORB Service,數據庫連接池等設置均合理,然后懷疑問題的現象是不是與系統GC有關。當前Java Virtual Machine的配置為: Initial Heap Size:256 , Maximum Heap Size: 3072。
為了驗證任務池中累積的任務數的大幅度變化和系統GC是否存在一定的關系,通過對任務池的累積任務數和系統GC進行采樣, 將采樣后的數據進行分析,用以得出二者的關系。采樣時遵循Nyquist采樣定例: 采樣頻率要大于被采集對象的頻率的2倍。 否則,采樣點很可能每次位于被采集對象的波形的某個點上,從而不能正確反映被采集對象的變化規律。
采樣
通過觀察,發現任務池的任務數目(以下用Q值代替)的變化周期大概是5到6秒,因此根據Nyquist采樣定例,采樣的時間間隔不能超過2-3秒,所以按照每秒來采樣。 測試時間是3分鐘,采樣180次,系統的當前負載率是99%。采樣圖如下所示:
圖一 任務池Q值的采樣圖
由于系流量控制要求的限額是450個任務,也就是任務池中最多能累積450個任務,當任務池中累積的任務數超過450時,多余的任務會被流量控制直接丟棄,從上圖可以看出,系統的Q值在很多時刻都大于450,因此多次被丟棄任務,從而導致了任務請求成功率不高。
系統GC的采樣
1: 在WebSphere Administrative Console上, 點擊進入:Servers, 然后Application servers > server1 > Process Definition > Java Virtual Machine, 在Configuration面板上,選上Verbose garbage collection選項。
圖二 WebSphere Application Server的JVM配置示圖
2:進入<%WebSphere Application Server的安裝目錄%>/profiles/<%所在的profiles%>/logs/ <%所在的Server%>, 可以看到native_stderr.log文件,將其清空
3:在高負載的條件下,進行高壓測試3分鐘
4:將native_stderr.log文件拷貝出來,用GCCollector工具進行分析,其中native_stderr.log文件上記錄了系統GC的數據。
5:安裝GCCollector工具: 下載完GCCollector.zip后,解壓縮,將里面Lib里的3個文件 jfreechart-1.0.0-rc1.jar,jcommon-1.0.0-rc1.jar 和GCCollector.jar拷貝至JRE的lib目錄下,然后在命令行控制臺上進入JRE的安裝目錄,而后運行: java -classpath jfreechart-1.0.0-rc1.jar;jcommon-1.0.0-rc1.jar -jar GCCollector.jar。
接著可以看到GCCollector的用戶界面,在它的Parser菜單中選擇JRE的版本,而后在File菜單中選擇并打開剛才拷出的native_stderr.log文件。
下圖是在高負載情況下,系統在當前配置下的GC分析圖。
圖三 系統的GC分析圖
由圖三可以看出,系統沒有內存泄漏的現象,每次GC所花的時間為220ms左右,從GCCollector的Spreadsheet可以查到,GC的時間周期為5-6 s,每次具體GC發生的時間,每次GC所花的時間。
6:同樣遵循Nyquist采樣定例,對GC進行采樣,采樣后的數據同任務池中Q值的采樣數據進行比較和分析,得出兩者之間存在著密切的關系。下圖為任務池Q值和GC數據采樣分析圖,由圖中可以看出,每次任務池的Q值大幅度增長時,系統剛好發生GC。二者的時間和周期幾乎可以完全匹配。 因此可以初步下一個結論,由于系統的GC,導致了系統在某些時刻不能有足夠的能力來處理請求,因此任務池的Q值在這些時候會因為任務的大量累積而巨幅漲大,即而超出限額的任務被流控所清除,導致了在超負荷下任務請求成功率不是很理想。
圖四 任務池Q值和GC數據采樣分析圖
解決方法
當前的GC發生的頻率和每次所花的時間還算正常,但是如果每次GC所花的CPU時間能減少,就能空出系統更多的能力處理任務池里的任務,用以降低任務池中的任務數,使得Q值基本上位于任務池的限額以下,這樣可以提高在超負荷下業務請求的總的成功率。
當前Java Virtual Machine的配置為: Initial Heap Size:256 , Maximum Heap Size: 3072。相對而言, Maximum Heap Size設的有點偏大。對于不同的應用程序,最優化堆大小的設置都有可能不同。堆設置變大,GC的頻率會降低,應用程序會運行更長的時間后,才會進行GC,帶來的就是每次GC也會花更長的時間。從而GC調用占用系統更長的時間,使系統沒有足夠的能力處理請求,使得此刻任務池中的任務累積很多,Q值很大,形成很高的峰值,超過流量控制的限額,超過限額數的任務被流量控制給直接丟棄,從而導致總的成功率不高。
因此,必須降低堆大小,使得GC的頻率增大,每次GC所花時間降低,從而降低Q的峰值,使之位于系統的流量控制的范圍之內,從而提高業務請求的總的成功率。
當前的流量控制所允許的峰值是450,因此我們需要通過試驗來驗證,堆大小降低到什么值時,Q值的峰值將低于450,以保證總的成功率。 同時在峰值低于450的條件下,什么樣的堆大小設置可以讓系統的性能最佳。 因為如果堆設置過小,會使得對象可分配空間變小,從而會頻繁的使用垃圾收集機制來釋放內存空間,而每次垃圾收集,都會耗用一定的系統資源。所以,我們要通過試驗和監控數據,設法使的我們所設置的堆大小能夠使得我們的程序運行最優化。
通過多次試驗,我們得出結論:當Java Virtual Machine的配置為: Initial Heap Size:512 , Maximum Heap Size: 1024時,該系統性能最佳。
從WebSphere Administrative Console上,依次點擊Servers->Application Servers,然后選擇需要的server,接著點擊Process Definition->Java Virtual Machine,而后在那里設置Initial Heap Size:512和Maximum Heap Size: 1024。這時的配置對于該應用系統相對較為合理。這時再次分析3分鐘內的GC的數據,從下圖可以看出,GC的周期縮短了,每1-2秒就會發生一次GC,但是每次GC所花費的CPU時間降低了,平均130ms左右。
圖五 改進JVM配置后的GC分析圖
相應地,在JVM配置改進后,對任務池的Q值再進行一次采樣,并且和改進前的采樣值進行比價,采樣圖如下圖六所示,改進后任務池的Q值分布在50-450之間,數值的起伏相對改進前要均衡些。不再出現忽然間Q值大小漲到500以上的情況,基本在流控的限制范圍之類,進而提高了在超負荷下業務請求的總的成功率。
圖六 改進JVM配置后和改進前的Q值采樣比較圖
總結
通過本文,我們可以看到系統JVM的配置和系統的性能有著比較大的關系,特別當系統的處理能力成某種變化趨勢時,要考慮到系統GC對系統性能的影響,為了找到兩者的關系,可以通過采樣,圖形比較來進行分析。如果發現二者之間有密切的聯系,可以考慮對JVM的配置進行優化,比如:對最優化堆的大小進行調整。
對于不同的應用程序,最優化堆大小的設置都有可能不同。如果堆設置較大,可能導致GC的次數變少,但每次GC所花的時間很長,從而導致系統的處理能力抖動很大。此外如果堆設置過大,會占用過多的內存,使內存資源耗盡,從而會頻繁的進行IO操作來使用虛擬內存。 如果堆設置較小,可能導致GC變的頻繁,但每次GC所花的時間不會太長,每次GC對系統的性能影響相對也會小些。但是如果堆設置過小, 會使得對象可分配空間變小,從而會頻繁的GC來釋放內存空間,而每次GC,都會耗用一定的系統資源。因此,要通過試驗和監控數據,設法使的我們所設置的堆大小能夠使得系統運行最優化。
參考資料
關于作者
|
|
|
李曉華, IBM CDL ODSC部門工程師,參與了中國電信3G大型項目. 寫作經歷:曾在國家核心期刊《計算機集成制造》(CIMS)發表文章:《面向異構過程庫的過程搜索方法與系統研究》。Email: xiaohual@cn.ibm.com
|