一次java性能調優經驗

 項目情況:是一個大型公司的內部辦公系統,該系統有兩個和一般企業應用不太一樣的特點:一是用戶量非常多,人員數達到2W左右,另一個是採用分級管理的形式,各個分公司數據分開管理。

我們的定位:我們是作爲業務平臺的提供商參與這個項目的,我們提供底層的開發平臺,系統集成商在此基礎上進行二次開發。

在項目從開發到部署的過程中遇到了很多的問題,也反映出很多問題。

一、怎麼回事,跑得比貓還慢
項目開發完畢後部署在Ibm aix 小型機上,32G內存,16個cpu。應用服務器採用的是weblogic9.2,數據庫是oracle10.0.2。上線後發現系統運行的非常緩慢,甚至比開發環境下的tomcat還要慢。於是開始排查原因,最開始是對SQL進行監控,優先考慮是數據庫訪問性能產生瓶頸。通過監控,發現很多業務需要執行大量的SQL語句,查看客戶編寫的相關代碼,發現在查詢數據時循環執行了大量SQL。主要原因在於他們在代碼中循環調用了我們相關API,一個最典型的例子是通過用戶ID查找用戶NAME,他們在業務表格裏沒有保存用戶name,而是在查詢的時候通過用戶ID查找用戶name填充到頁面,幾乎每一個查詢都是n+1。
 
另外由於平臺使用了hibernate,使得oo編程得非常爽快,導致開發人員完全忽略了相應的數據庫操作所帶來的壓力。很多業務邏輯直接通過PO疊加完成,把一些可以通過很少SQL完成的邏輯全部分散放置到PO裏,導致了大量PO的交互和SQL語句。

開始優化SQL,優化的同時增加大量業務緩存。但優化完畢後運行緩慢的現象依舊存在,性能有了一定的提升但是不是非常明顯。繼續優化,其中考慮過多頻繁訪問的數據使用內存數據庫的方式。但是優化過後在tomcat上效果明顯,部署到生產環境就問題依舊。於是考慮weblogic的配置問題,作爲開發平臺提供商,我們只是提供系統開發相關方面的支持,對於應用服務器和數據庫服務器只是做基本的配置系統可運行即可。但是在這個問題上系統集成商咬定是我們平臺的問題不放,並且存在一個很嚴重的問題:他們使用的是盜版的weblogic,這樣根本就沒有相應的技術支持。

問題的解決:最後是找了一個BEA曾經的開發人員,問題實際非常的簡單,現場部署的weblogic默認是運行在32位機器上,與64位機器存在一定的不兼容。通過替換相應的jar包,問題得到了解決,主要是IO方面。替換完畢後,速度提升了進30% 。該開發人員說,如果沒有lisence,根本就不會得到這些替換的jar包。

二、內存耗盡了
訪問速度的問題解決了,系統的使用量很快上來,馬上遇到新的問題:內存耗盡了。嚴重到幾乎每天都要out of memory一次。這種問題在客戶現場頻繁出現。

本地測試,tomcat,sun jdk 通過Jprofiler監測內存使用情況。在併發訪問門戶的情況下,內存確實存在暴漲的情況,100併發,內存使用立刻上升了150m左右,繼續併發 100,再增長150m。但是很快在抵達高峯時會有一次gc發生,內存使用穩定在200m,內存裏大量char[]數組對象。疲勞測試,內存使用曲線並沒有出現逐漸上升泄露的情況。換weblogic和jrocket測試,gc發生的更加頻繁,內存使用穩定。
 
但是現場依舊頻繁當機,內存根本釋放不了,一直逐漸增長,典型的內存泄露。對系統緩存、單態對象包括spring管理的對象、IO流進行了統一排查,依舊沒有找到內存泄露的原因。使用IBM 工具分析heapdump文件,結果還是大量的char[]數組對象佔據內存,查找應用,找不到相關業務對象引用。
 
問題解決:問題解決是一篇偶爾搜到的oracle論壇的帖子,這裏http://forums.oracle.com/forums/message.jspa?messageID=1040570 。原因在於oracle10的數據庫驅動對statement最後執行的結果集有着引用,並且不會釋放,目的在於通過內存而換取更好的性能。數據庫連接採用的是weblogic的連接池,關於connection有個相關的statement cache設定,設定一個connection能夠被緩存的statement個數,最大是1024,而現場就被設定爲了1024!connection pool的connection個數被設置爲了500 。真是個恐怖的設置。在將1024改爲10後,內存使用量轟然倒地,穩定在1g左右。這個設置是在前面系統訪問速度存在問題時由系統集成商的開發人員設置上去的,他們將所有和優化相關的參數全部開到了最大。這個問題要是用戶購買的是正版的weblogic和oracle的話,相信也會很快得到解決。

三、線程阻塞
內存泄露的問題解決後,線程阻塞的問題浮出水面。系統集成商報告是線程死鎖,通過分析工具其實是線程阻塞,主要問題在於系統用到了 synchronized關鍵字,對工作流相關API全部使用了synchronized,原因在這裏:http: //ronghao.javaeye.com/blog/205731 。分析發現一個工作項提交的操作在連接數據庫時被掛起了20分鐘!造成了大量線程的排隊阻塞。被掛起的原因有很多種。我們採用的方法是將接口拆分和設置事務timeout時間。但是這顯然不是一個好方法。最後是去掉所有的synchronized關鍵字,將同步的問題交由數據庫解決,問題解決。

四、反思
1、系統集成商爲什麼不購買正版?
2、開發平臺提供商究竟在項目開發中處於一種什麼樣的位置?開發平臺是否對所有軟件開發問題都要負責?
3、開發平臺是越封裝越快樂嗎?還是越封裝越醜陋?

更具體的細節在這裏:

 AIX+weblogic性能診斷記錄



http://www.blogjava.net/ronghao 榮浩原創,轉載請註明出處
發佈了40 篇原創文章 · 獲贊 59 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章