
一位ID是jackson1225的網(wǎng)友在javaeye詢問了一個大型Web系統(tǒng)的架構(gòu)和部署選型問題,希望能提高現(xiàn)有的基于Java的Web應(yīng)用的服務(wù)能力。由于架構(gòu)模式和部署調(diào)優(yōu)一直是Java社區(qū)的熱門話題,這個問題引發(fā)了很多熱心網(wǎng)友的討論,其中一些意見對其它大型Web項目也有很好的指導(dǎo)意義。在討論之初jackson1225這樣描述了當(dāng)前的應(yīng)用的架構(gòu)和部署方案:
目前系統(tǒng)架構(gòu)如下:
- web層采用struts+tomcat實現(xiàn),整個系統(tǒng)采用20多臺web服務(wù)器,其負(fù)載均衡采用硬件F5來實現(xiàn);
- 中間層采用無狀態(tài)會話Bean+DAO+helper類來實現(xiàn),共3臺weblogic服務(wù)器,部署有多個EJB,其負(fù)載均衡也采用F5來實現(xiàn);
- 數(shù)據(jù)庫層的操作是自己寫的通用類實現(xiàn)的,兩臺ORACLE數(shù)據(jù)庫服務(wù)器,分別存放用戶信息和業(yè)務(wù)數(shù)據(jù);一臺SQL SERVER數(shù)據(jù)庫,是第三方的業(yè)務(wù)數(shù)據(jù)信息;
web層調(diào)用EJB遠(yuǎn)程接口來訪問中間件層。web層首先通過一個XML配置文件中配置的EJB接口信息來調(diào)用相應(yīng)的EJB遠(yuǎn)程接口;
該系統(tǒng)中一次操作涉及到兩個ORACLE庫以及一個SQL SERVER庫的訪問和操作,即有三個數(shù)據(jù)庫連接,在一個事務(wù)中完成。
這樣的架構(gòu)其實很多公司都在使用,因為Struts和Tomcat分別是最流行的Java Web MVC框架和Servlet容器,而F5公司的負(fù)載均衡是橫向擴(kuò)展常見的解決方案(例如配置session sticky方案)。由于這個系統(tǒng)中有跨數(shù)據(jù)源的事務(wù),所以使用Weblogic Server EJB容器和支持兩階段提交的數(shù)據(jù)庫驅(qū)動就可以保證跨數(shù)據(jù)源的事物完整性(當(dāng)然,容器管理的分布式事務(wù)并非是唯一和最優(yōu)的解決方案)。
但是隨著Rod Johnson重量級的著作《J2EE Development without EJB》和其中的Spring框架的流行,輕量級框架和輕量級容器的概念已經(jīng)深入人心。所以對于jackson1225提出的這個場景,大多數(shù)網(wǎng)友都提出了置疑,認(rèn)為這個系統(tǒng)濫用了技術(shù),完全是在浪費(fèi)錢。網(wǎng)友們大都認(rèn)為SLSB(無狀態(tài)會話Bean)完全沒有必要出現(xiàn)在這個場景中,認(rèn)為SLSB通過遠(yuǎn)程接口訪問本地資源會有很大的性能開銷,這種觀點(diǎn)也是Rod johnson在without EJB中批判EJB 2.x中的一大反模式。
由于JavaEE是一個以模式見長的解決方案,模式和架構(gòu)在JavaEE中占有很重要的地位,所以很多業(yè)內(nèi)專家也都警惕“反模式(Anti-patterns)”的出現(xiàn)。對于上面所述的方案是否是反模式,jackson1225馬上站出來申辯:
我們項目就是把EJB作為一個Facade,只是提供給WEB層調(diào)用的遠(yuǎn)程接口,而且只用了無狀態(tài)會話Bean,所以性能上還可以的。
這個解釋很快得到了一些網(wǎng)友的認(rèn)可,但是大家很快意識到架構(gòu)的好壞決定于是否能夠滿足用戶的需求,davexin(可能是jackson1225的同事)描述了這個系統(tǒng)的用戶和并發(fā)情況:
現(xiàn)在有用戶4000萬,馬上要和另一個公司的會員系統(tǒng)合并,加起來一共有9000萬用戶。數(shù)據(jù)量單表中有一億條以上的數(shù)據(jù)。這是基本的情況,其實我覺得現(xiàn)在的架構(gòu)還是可以的,現(xiàn)在支持的并發(fā)大概5000并發(fā)用戶左右,接下來會進(jìn)行系統(tǒng)改造,目標(biāo)支持1萬個并發(fā)用戶。
具體的并發(fā)量公布后又有網(wǎng)友置疑這個數(shù)據(jù),認(rèn)為這個系統(tǒng)的Servlet容器支持的并發(fā)數(shù)太小,懷疑是否配置不夠優(yōu)化。davexin又補(bǔ)充了該項目的服務(wù)器配置:
系統(tǒng)前端tomcat都是用的刀片,配置在2G內(nèi)存,cpu大概在2.0G,每臺機(jī)器也就支持250-400個并發(fā),再多的話,就會相應(yīng)時間非常的常,超過20秒,失去了意義 ,所以我們才得出這樣的結(jié)論的。
一位ID是cauherk的網(wǎng)友提出了比較中肯的意見,他沒有從Web容器單純的并發(fā)支持能力上提出改進(jìn)方案,而是提出了對于類似的應(yīng)用的一些通用的改進(jìn)提示,這里摘要一下:
- 數(shù)據(jù)庫壓力問題
可以按照業(yè)務(wù)、區(qū)域等等特性對數(shù)據(jù)庫進(jìn)行配置,可以考慮分庫、使用rac、分區(qū)、分表等等策略,確保數(shù)據(jù)庫能正常的進(jìn)行交易。
- 事務(wù)問題
要在兩個數(shù)據(jù)庫中操作,那么必須考慮到分布式事務(wù)。你應(yīng)該仔細(xì)的設(shè)計你的系統(tǒng),來避免使用分布式事務(wù),以避免分布式事務(wù)帶來更多的數(shù)據(jù)庫壓力和其它問題。推薦你采用延遲提交的策略(并不保證數(shù)據(jù)的完整),來避免分布式事務(wù)的問題,畢竟commit失敗的幾率很低。
- web的優(yōu)化
將靜態(tài)、圖片獨(dú)立使用不同的服務(wù)器,對于常態(tài)的靜態(tài)文件,采用E-TAG或者客戶端緩存, google很多就是這樣干的。對于熱點(diǎn)的功能,考慮使用完全裝載到內(nèi)存,保證絕對的響應(yīng)速度,對于需要頻繁訪問的熱點(diǎn)數(shù)據(jù),采用集中緩存(多個可以采用負(fù)載均衡),減輕數(shù)據(jù)庫的壓力。
對于幾乎除二進(jìn)制文件,都應(yīng)該在L4上配置基于硬件的壓縮方案,減少網(wǎng)絡(luò)的流量。提高用戶使用的感知。
- 網(wǎng)絡(luò)問題
可以考慮采用鏡像、多路網(wǎng)絡(luò)接入、基于DNS的負(fù)載均衡。如果有足夠的投資,可以采用CDN(內(nèi)容分發(fā)網(wǎng)),減輕你的服務(wù)器壓力。
cauherk的這個分析比較到位,其中ETags的方案是最近的一個熱點(diǎn),InfoQ的“使用ETags減少Web應(yīng)用帶寬和負(fù)載”里面對這種方案有很詳細(xì)的介紹。一般以數(shù)據(jù)庫為中心的Web應(yīng)用的性能瓶頸都在數(shù)據(jù)庫上,所以cauherk把數(shù)據(jù)庫和事務(wù)問題放到了前兩位來討論。但是davexin解釋在所討論的這個項目中數(shù)據(jù)庫并非瓶頸:
我們的壓力不在數(shù)據(jù)庫層,在web層和F5。 當(dāng)高峰的時候 ,F(xiàn)5也被點(diǎn)死了,就是每秒點(diǎn)擊超過30萬,web動態(tài)部分根本承受不了。根據(jù)我們程序記錄,20臺web最多承受5000個并發(fā),如果再多,tomcat就不響應(yīng)了。就像死了一樣。
這個回復(fù)讓接下來的討論都集中于Web容器的性能優(yōu)化,但是JavaEye站長robbin發(fā)表了自己的意見,將話題引回了這個項目的架構(gòu)本身:
performance tuning最重要的就是定位瓶頸在哪里,以及瓶頸是怎么產(chǎn)生的。
我的推測是瓶頸還是出在EJB遠(yuǎn)程方法調(diào)用上!
tomcat上面的java應(yīng)用要通過EJB遠(yuǎn)程方法調(diào)用,來訪問weblogic上面的無狀態(tài)SessionBean,這樣的遠(yuǎn)程方法調(diào)用一般都在100ms~500ms級別,或者更多。而如果沒有遠(yuǎn)程方法調(diào)用,即使大量采用spring的動態(tài)反射,一次完整的web請求處理在本地JVM內(nèi)部的完成時間一般也不過20ms而已。一次web請求需要過長的執(zhí)行時間,就會導(dǎo)致servlet線程被占用更多的時間,從而無法及時響應(yīng)更多的后續(xù)請求。
如果這個推測是成立的話,那么我的建議就是既然你沒有用到分布式事務(wù),那么就干脆去掉EJB。weblogic也可以全部撤掉,業(yè)務(wù)層使用spring取代EJB,不要搞分布式架構(gòu),在每個tomcat實例上面部署一個完整的分層結(jié)構(gòu)。
另外在高并發(fā)情況下,apache處理靜態(tài)資源也很耗內(nèi)存和CPU,可以考慮用輕量級web server如lighttpd/litespeed/nginx取代之。
robbin的推斷得到了網(wǎng)友們的支持,davexin也認(rèn)同robbin的看法,但是他解釋說公司認(rèn)為放棄SLSB存在風(fēng)險,所以公司傾向于通過將Tomcat替換為Weblogic Server 10來提升系統(tǒng)的用戶支撐能力。robbin則馬上批評了這種做法:
坦白說我還從來沒有聽說過大規(guī)?;ヂ?lián)網(wǎng)應(yīng)用使用EJB的先例。為什么大規(guī)?;ヂ?lián)網(wǎng)應(yīng)用不能用EJB,其實就是因為EJB性能太差,用了EJB幾乎必然出現(xiàn)性能障礙。
web容器的性能說到底無非就是Servlet線程調(diào)度能力而已,Tomcat不像WebLogic那樣附加n多管理功能,跑得快很正常。對比測試一下WebLogic的數(shù)據(jù)庫連接池和C3P0連接池的性能也會發(fā)現(xiàn)類似的結(jié)論,C3P0可要比WebLogic的連接池快好幾倍了。這不是說WebLogic性能不好,只不過weblogic要實現(xiàn)更多的功能,所以在單一的速度方面就會犧牲很多東西。
以我的經(jīng)驗來判斷,使用tomcat5.5以上的版本,配置apr支持,進(jìn)行必要的tuning,使用BEA JRockit JVM的話,在你們目前的刀片上面,支撐500個并發(fā)完全是可以做到的。結(jié)合你們目前20個刀片的硬件,那么達(dá)到1萬并發(fā)是沒問題的。當(dāng)然這樣做的前提是必須扔掉EJB,并置web層和業(yè)務(wù)層在同一個JVM內(nèi)部。
接下來robbin還針對davexin對話題中的應(yīng)用分別在tomcat和weblogic上的測試數(shù)據(jù)進(jìn)行了分析:
引用:2。1臺weblogic10 Express(相當(dāng)于1臺tomcat,用于發(fā)布jsp應(yīng)用)加1臺weblogic10(發(fā)布ejb應(yīng)用),能支持1000個并發(fā)用戶......
......
4。1臺tomcat4.1加1臺weblogic8,只能支持350個并發(fā)用戶,tomcat就連結(jié)超時,說明此種結(jié)構(gòu)瓶頸在tomcat。這說明瓶頸還不在EJB遠(yuǎn)程調(diào)用上,但是問題已經(jīng)逐漸清楚了。為什么weblogic充當(dāng)web容器發(fā)起遠(yuǎn)程EJB調(diào)用的時候可以支撐1000個并發(fā),但是tomcat只能到350個?只有兩個可能的原因:
- 你的tomcat沒有配置好,嚴(yán)重影響了性能表現(xiàn)
- tomcat和weblogic之間的接口出了問題
接著springside項目發(fā)起者江南白衣也提出了一個總體的優(yōu)化指導(dǎo):
1.基礎(chǔ)配置優(yōu)化
tomcat 6? tomcat參數(shù)調(diào)優(yōu)?
JRockit JVM? JVM參數(shù)調(diào)優(yōu)?
Apache+Squid 處理靜態(tài)內(nèi)容?2.業(yè)務(wù)層優(yōu)化
部分功能本地化,而不調(diào)remote session bean?
異步提交操作,JMS?
cache熱點(diǎn)數(shù)據(jù)?3.展示層優(yōu)化
動態(tài)頁面發(fā)布為靜態(tài)頁面?
Cache部分動態(tài)頁面內(nèi)容?
davexin在調(diào)整了Tomcat配置后應(yīng)驗了robbin對tomcat配置問題的質(zhì)疑,davexin這樣描述經(jīng)過配置優(yōu)化以后的測試結(jié)果:
經(jīng)過測試,并發(fā)人數(shù)是可以達(dá)到像robbin所說的一樣,能夠在600人左右,如果壓到并發(fā)700人,就有15%左右的失敗,雖然在調(diào)整上面參數(shù)之后,并發(fā)人數(shù)上去了,但是在同樣的時間內(nèi)所完成的事務(wù)數(shù)量下降了10%左右,并且響應(yīng)時間延遲了1秒左右,但從整體上來說,犧牲一點(diǎn)事務(wù)吞吐量和響應(yīng)時間,并發(fā)人數(shù)能夠提高500,覺得還是值得的。
至此這個話題有了一個比較好的結(jié)果。這個話題并非完全針對一個具體的項目才有意義,更重要的是在分析和討論問題的過程中網(wǎng)友們解決問題的思路,尤其是cauherk、robbin、江南白衣等幾位網(wǎng)友提出的意見可以讓廣大Java Web項目開發(fā)者了解到中、大型項目所需要考慮的架構(gòu)和部署所需要考慮的關(guān)鍵問題,也消除了很多人對輕量Servlet容器與EJB容器性能的一些誤解。
在討論中還有一些小插曲,如davexin和江南白衣討論了JRocket的實時(Realtime)版本是否可以提升Servlet容器的相應(yīng)能力,答案是不可以。還有ID為mfc42d的網(wǎng)友從Servlet容器的并發(fā)支持能力引申到了Java的線程調(diào)度能力和NIO對Servelet容器的意義,他推薦了自己的兩篇不錯的blog“java的線程實現(xiàn)”和“java進(jìn)程使用的最大內(nèi)存的數(shù)值”,blog文章里面從JVM源碼級別分析了Java的線程支持能力,面臨JVM性能調(diào)優(yōu)問題的網(wǎng)友可以認(rèn)真閱讀一下。