項(xiàng)目情況:是一個(gè)大型公司的內(nèi)部辦公系統(tǒng),該系統(tǒng)有兩個(gè)和一般企業(yè)應(yīng)用不太一樣的特點(diǎn):一是用戶量非常多,人員數(shù)達(dá)到2W左右,另一個(gè)是采用分級(jí)管理的形式,各個(gè)分公司數(shù)據(jù)分開管理。
我們的定位:我們是作為業(yè)務(wù)平臺(tái)的提供商參與這個(gè)項(xiàng)目的,我們提供底層的開發(fā)平臺(tái),系統(tǒng)集成商在此基礎(chǔ)上進(jìn)行二次開發(fā)。
在項(xiàng)目從開發(fā)到部署的過程中遇到了很多的問題,也反映出很多問題。
一、怎么回事,跑得比貓還慢
項(xiàng)目開發(fā)完畢后部署在Ibm aix
小型機(jī)上,32G內(nèi)存,16個(gè)cpu。應(yīng)用服務(wù)器采用的是weblogic9.2,數(shù)據(jù)庫是oracle10.0.2。上線后發(fā)現(xiàn)系統(tǒng)運(yùn)行的非常緩慢,甚
至比開發(fā)環(huán)境下的tomcat還要慢。于是開始排查原因,最開始是對(duì)SQL進(jìn)行監(jiān)控,優(yōu)先考慮是數(shù)據(jù)庫訪問性能產(chǎn)生瓶頸。通過監(jiān)控,發(fā)現(xiàn)很多業(yè)務(wù)需要執(zhí)行
大量的SQL語句,查看客戶編寫的相關(guān)代碼,發(fā)現(xiàn)在查詢數(shù)據(jù)時(shí)循環(huán)執(zhí)行了大量SQL。主要原因在于他們?cè)诖a中循環(huán)調(diào)用了我們相關(guān)API,一個(gè)最典型的例
子是通過用戶ID查找用戶NAME,他們?cè)跇I(yè)務(wù)表格里沒有保存用戶name,而是在查詢的時(shí)候通過用戶ID查找用戶name填充到頁面,幾乎每一個(gè)查詢都
是n+1。
另外由于平臺(tái)使用了hibernate,使得oo編程得非常爽快,導(dǎo)致開發(fā)人員完全忽略了相應(yīng)的數(shù)據(jù)庫操作所帶來的壓力。很多業(yè)務(wù)邏輯直接通過PO疊加完成,把一些可以通過很少SQL完成的邏輯全部分散放置到PO里,導(dǎo)致了大量PO的交互和SQL語句。
開始優(yōu)化SQL,優(yōu)化的同時(shí)增加大量業(yè)務(wù)緩存。但優(yōu)化完畢后運(yùn)行緩慢的現(xiàn)象依舊存在,性能有了一定的提升但是不是非常明顯。繼續(xù)優(yōu)化,其中考慮過
多頻繁訪問的數(shù)據(jù)使用內(nèi)存數(shù)據(jù)庫的方式。但是優(yōu)化過后在tomcat上效果明顯,部署到生產(chǎn)環(huán)境就問題依舊。于是考慮weblogic的配置問題,作為開
發(fā)平臺(tái)提供商,我們只是提供系統(tǒng)開發(fā)相關(guān)方面的支持,對(duì)于應(yīng)用服務(wù)器和數(shù)據(jù)庫服務(wù)器只是做基本的配置系統(tǒng)可運(yùn)行即可。但是在這個(gè)問題上系統(tǒng)集成商咬定是我
們平臺(tái)的問題不放,并且存在一個(gè)很嚴(yán)重的問題:他們使用的是盜版的weblogic,這樣根本就沒有相應(yīng)的技術(shù)支持。
問題的解決:最后是找了一個(gè)BEA曾經(jīng)的開發(fā)人員,問題實(shí)際非常的簡(jiǎn)單,現(xiàn)場(chǎng)部署的weblogic默認(rèn)是運(yùn)行在32位機(jī)器上,與64位機(jī)器存
在一定的不兼容。通過替換相應(yīng)的jar包,問題得到了解決,主要是IO方面。替換完畢后,速度提升了進(jìn)30%
。該開發(fā)人員說,如果沒有l(wèi)isence,根本就不會(huì)得到這些替換的jar包。
二、內(nèi)存耗盡了
訪問速度的問題解決了,系統(tǒng)的使用量很快上來,馬上遇到新的問題:內(nèi)存耗盡了。嚴(yán)重到幾乎每天都要out of memory一次。這種問題在客戶現(xiàn)場(chǎng)頻繁出現(xiàn)。
本地測(cè)試,tomcat,sun jdk
通過Jprofiler監(jiān)測(cè)內(nèi)存使用情況。在并發(fā)訪問門戶的情況下,內(nèi)存確實(shí)存在暴漲的情況,100并發(fā),內(nèi)存使用立刻上升了150m左右,繼續(xù)并發(fā)
100,再增長150m。但是很快在抵達(dá)高峰時(shí)會(huì)有一次gc發(fā)生,內(nèi)存使用穩(wěn)定在200m,內(nèi)存里大量char[]數(shù)組對(duì)象。疲勞測(cè)試,內(nèi)存使用曲線并沒
有出現(xiàn)逐漸上升泄露的情況。換weblogic和jrocket測(cè)試,gc發(fā)生的更加頻繁,內(nèi)存使用穩(wěn)定。
但是現(xiàn)場(chǎng)依舊頻繁當(dāng)機(jī),內(nèi)存根本釋放不了,一直逐漸增長,典型的內(nèi)存泄露。對(duì)系統(tǒng)緩存、單態(tài)對(duì)象包括spring管理的對(duì)象、IO流進(jìn)行了統(tǒng)一
排查,依舊沒有找到內(nèi)存泄露的原因。使用IBM
工具分析heapdump文件,結(jié)果還是大量的char[]數(shù)組對(duì)象占據(jù)內(nèi)存,查找應(yīng)用,找不到相關(guān)業(yè)務(wù)對(duì)象引用。
問題解決:?jiǎn)栴}解決是一篇偶爾搜到的oracle論壇的帖子,這里
http://forums.oracle.com/forums/message.jspa?messageID=1040570
。原因在于oracle10的數(shù)據(jù)庫驅(qū)動(dòng)對(duì)statement最后執(zhí)行的結(jié)果集有著引用,并且不會(huì)釋放,目的在于通過內(nèi)存而換取更好的性能。數(shù)據(jù)庫連接采
用的是weblogic的連接池,關(guān)于connection有個(gè)相關(guān)的statement
cache設(shè)定,設(shè)定一個(gè)connection能夠被緩存的statement個(gè)數(shù),最大是1024,而現(xiàn)場(chǎng)就被設(shè)定為了1024!connection
pool的connection個(gè)數(shù)被設(shè)置為了500
。真是個(gè)恐怖的設(shè)置。在將1024改為10后,內(nèi)存使用量轟然倒地,穩(wěn)定在1g左右。這個(gè)設(shè)置是在前面系統(tǒng)訪問速度存在問題時(shí)由系統(tǒng)集成商的開發(fā)人員設(shè)置
上去的,他們將所有和優(yōu)化相關(guān)的參數(shù)全部開到了最大。這個(gè)問題要是用戶購買的是正版的weblogic和oracle的話,相信也會(huì)很快得到解決。
三、線程阻塞
內(nèi)存泄露的問題解決后,線程阻塞的問題浮出水面。系統(tǒng)集成商報(bào)告是線程死鎖,通過分析工具其實(shí)是線程阻塞,主要問題在于系統(tǒng)用到了
synchronized關(guān)鍵字,對(duì)工作流相關(guān)API全部使用了synchronized,原因在這里:
http:
//ronghao.javaeye.com/blog/205731
。分析發(fā)現(xiàn)一個(gè)工作項(xiàng)提交的操作在連接數(shù)據(jù)庫時(shí)被掛起了20分鐘!造成了大量線程的排隊(duì)阻塞。被掛起的原因有很多種。我們采用的方法是將接口拆分和設(shè)置事
務(wù)timeout時(shí)間。但是這顯然不是一個(gè)好方法。最后是去掉所有的synchronized關(guān)鍵字,將同步的問題交由數(shù)據(jù)庫解決,問題解決。
四、反思
1、系統(tǒng)集成商為什么不購買正版?
2、開發(fā)平臺(tái)提供商究竟在項(xiàng)目開發(fā)中處于一種什么樣的位置?開發(fā)平臺(tái)是否對(duì)所有軟件開發(fā)問題都要負(fù)責(zé)?
3、開發(fā)平臺(tái)是越封裝越快樂嗎?還是越封裝越丑陋?
更具體的細(xì)節(jié)在這里:
http://www.tkk7.com/ronghao 榮浩原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處:)
posted on 2008-09-01 13:49
ronghao 閱讀(4114)
評(píng)論(10) 編輯 收藏 所屬分類:
工作日志