原鏈接
Uncover the hood of J2EE Clustering
1 前言
越來(lái)越多的關(guān)鍵任務(wù)和大型應(yīng)用正運(yùn)行在J2EE平臺(tái)上,象銀行之類的應(yīng)用要求很高的可用性(HA),大型系統(tǒng)比如google和Yahoo則要求更好的伸 縮性。今天高可用性和伸縮性的重要性對(duì)于互聯(lián)世界日益增長(zhǎng),最著名的證明是1999年eBay中斷了22小時(shí)的服務(wù),原因是超過(guò)230萬(wàn)次的拍賣,最終導(dǎo) 致eBay股票下跌了9.2個(gè)百分點(diǎn)。
J2EE集群是最常用的技術(shù),用來(lái)提供高可用性和伸縮性的容錯(cuò)服務(wù)。但由于缺乏J2EE規(guī)范的支持,J2EE提供廠商實(shí)現(xiàn)的集群盡不相同,引起許多J2EE架構(gòu)師和開發(fā)者的麻煩,比如下面:
1. 為什么附帶集群能力的商業(yè)J2EE服務(wù)器如此昂貴?(比不帶集群能力的貴10倍)
2. 為什么我在單機(jī)上創(chuàng)建的應(yīng)用無(wú)法運(yùn)行在集群模式?
3. 為什么我的應(yīng)用在集群時(shí)運(yùn)行緩慢但不集群時(shí)卻很快速?
4. 為什么我的集群應(yīng)用不能與其他提供商的服務(wù)器通信?
2 基本術(shù)語(yǔ)
討論不同實(shí)現(xiàn)之前,理解集群技術(shù)的概念是很有意義的,我希望不僅能給你提供關(guān)于J2EE集群產(chǎn)品基本的設(shè)計(jì)理念和概念,還可以概括性的描繪不同的集群實(shí)現(xiàn),使它們更容易被理解。
2.1 伸縮性(Scalability)
大型系統(tǒng)很難預(yù)測(cè)終端用戶的數(shù)量與行為,伸縮性是指系統(tǒng)可以支持用戶的快速增長(zhǎng)。提高服務(wù)器同時(shí)處理并發(fā)會(huì)話的最直覺的方式就是增加服務(wù)器資源(內(nèi)存, CPU,或硬盤),集群是解決伸縮性的另一種可選方式。它允許一組服務(wù)器分擔(dān)處理繁重的任務(wù),而邏輯上就象一臺(tái)服務(wù)器一樣。
2.2 高可用性(High Availability)
提高伸縮性的單服務(wù)器解決方案(添加內(nèi)存和CPU)是并不強(qiáng)壯的辦法,因?yàn)閱吸c(diǎn)失效原因。關(guān)鍵任務(wù)應(yīng)用不能容忍服務(wù)中斷哪怕一分鐘。它要求任何時(shí)候都可以合理地可預(yù)期的響應(yīng)時(shí)間訪問(wèn)這些服務(wù),集群可以通過(guò)提供額外的服務(wù)器使其在一臺(tái)服務(wù)器實(shí)效時(shí)提供服務(wù),從而提高可用性。
2.3 負(fù)載均衡(Load balancing)
負(fù)載均衡是集群技術(shù)之后的一個(gè)關(guān)鍵技術(shù),通過(guò)分發(fā)請(qǐng)求到不同的服務(wù)器來(lái)提高可用性和更好的性能。負(fù)載均衡器可以是一個(gè)Servlet或插件(例如a linux box using ipchains),除分發(fā)請(qǐng)求之外,負(fù)載均衡器應(yīng)負(fù)責(zé)其他一些重要的任務(wù),例如“會(huì)話黏附”,使得某個(gè)用戶會(huì)話始終在一臺(tái)服務(wù)器上存活,還有“心跳檢 測(cè)”,防止分發(fā)請(qǐng)求到失效的服務(wù)器。有時(shí)候負(fù)載均衡器也參與到“失效轉(zhuǎn)移”處理。
2.4 容錯(cuò)(Fault Tolerance)
高可用性數(shù)據(jù)不必是嚴(yán)格正確數(shù)據(jù).在J2EE集群中,當(dāng)一個(gè)服務(wù)器實(shí)例失效時(shí),服務(wù)仍然可用,因?yàn)樾碌恼?qǐng)求可由其他冗余的服務(wù)器實(shí)例處理。但如果請(qǐng)求正在處理當(dāng)中時(shí)服務(wù)器實(shí)例失效,則不能能得到正確的數(shù)據(jù)。然而容錯(cuò)服務(wù)則總是保證嚴(yán)格正確的行為。
2.5 失效轉(zhuǎn)移(Failover)
失效轉(zhuǎn)移是另一項(xiàng)使得集群實(shí)現(xiàn)容錯(cuò)的關(guān)鍵技術(shù)。通過(guò)選擇集群中另一個(gè)節(jié)點(diǎn),原始節(jié)點(diǎn)失效時(shí)處理將繼續(xù)下去。失效轉(zhuǎn)移可以顯式地編碼也可以由低層平臺(tái)自動(dòng)執(zhí)行。
2.6 等冪方法(Idempotent methods)
可以用相同的參數(shù)重復(fù)調(diào)用的方法,并且總是得到相同的結(jié)果。這些方法不應(yīng)該影響系統(tǒng)狀態(tài),可以被重復(fù)地調(diào)用而不必?fù)?dān)心改變系統(tǒng)。例如, “getUsername()” 是等冪方法,而“deleteFile()” 就不是等冪方法。等冪是HTTP會(huì)話和EJB失效轉(zhuǎn)移的重要概念。
3 J2EE集群是什么?
一個(gè)幼稚的問(wèn)題,不是嗎?但我仍然用一些話語(yǔ)和圖表來(lái)回答它。通常J2EE集群技術(shù)包括“負(fù)載均衡”和“失效轉(zhuǎn)移”。

圖1 負(fù)載均衡
如圖1所示,有很多客戶端對(duì)象并發(fā)發(fā)送請(qǐng)求到目標(biāo)對(duì)象。負(fù)載均衡器則位于調(diào)用者和被調(diào)用者之間,分發(fā)請(qǐng)求到冗余的擁有同樣功能的對(duì)象上。用此方法可以實(shí)現(xiàn)高可用性和高性能。

圖2:失效轉(zhuǎn)移
如圖2所示,失效轉(zhuǎn)移與負(fù)載均衡不同。有時(shí)候,客戶端對(duì)象對(duì)目標(biāo)對(duì)象發(fā)起連續(xù)的方法請(qǐng)求。如果目標(biāo)對(duì)象在請(qǐng)求之間失效,失效轉(zhuǎn)移系統(tǒng)應(yīng)該檢測(cè)到并將后續(xù)請(qǐng)求轉(zhuǎn)向?qū)Я硪粋€(gè)可用的對(duì)象,容錯(cuò)也可用此途徑實(shí)現(xiàn)。
如果想了解更多J2EE集群,你應(yīng)該問(wèn)更多的基本問(wèn)題,例如:“什么類型的對(duì)象可以被集群?”,“在我的J2EE代碼中什么地方出現(xiàn)負(fù)載均衡和失效轉(zhuǎn) 移?”,對(duì)于理解J2EE集群的原理,這些都是非常好的問(wèn)題。實(shí)際上,不是所有對(duì)象可以被集群,也不是任何地方都可以負(fù)載均衡和失效轉(zhuǎn)移!看看下列代碼:

圖3:代碼例子
當(dāng)“instance1”失效時(shí),“Class A”的“business()”方法會(huì)負(fù)載均衡和失效轉(zhuǎn)移到另一個(gè)B實(shí)例嗎?不,不會(huì)。對(duì)于負(fù)載均衡和失效轉(zhuǎn)移,必須要在調(diào)用者和被調(diào)用者之間存在一個(gè)攔 截器,用來(lái)分發(fā)或者轉(zhuǎn)向方法調(diào)用到不同的對(duì)象上。A和B的實(shí)例對(duì)象運(yùn)行在同一個(gè)JVM上,并緊密耦合。很難在方法調(diào)用之間添加分發(fā)邏輯。
所以,什么類型的對(duì)象可以被集群?---只有發(fā)布在分布式結(jié)構(gòu)的對(duì)象。
所以,什么地方會(huì)發(fā)生負(fù)載均衡和失效轉(zhuǎn)移呢?--只有在調(diào)用一個(gè)分布式對(duì)象的方法時(shí)。

圖4:分布式對(duì)象
在分布式環(huán)境,如圖4所示,調(diào)用者和被調(diào)用者被分離為不同邊界的運(yùn)行容器,邊界是JVM,進(jìn)程或機(jī)器。
當(dāng)客戶端調(diào)用目標(biāo)對(duì)象時(shí),在目標(biāo)對(duì)象容器內(nèi)執(zhí)行功能。客戶端和目標(biāo)對(duì)象通過(guò)標(biāo)準(zhǔn)的網(wǎng)絡(luò)協(xié)議通信。利用這些特性添加機(jī)制到方法調(diào)用路由中,以實(shí)現(xiàn)負(fù)載均衡和失效轉(zhuǎn)移。
如圖4所示,瀏覽器可以通過(guò)HTTP協(xié)議調(diào)用遠(yuǎn)程JSP對(duì)象。JSP在Web服務(wù)器上執(zhí)行,瀏覽器不關(guān)心執(zhí)行過(guò)程,它只需要結(jié)果。在這樣的場(chǎng)景中,有些東 西可以位于瀏覽器和web服務(wù)器之間用來(lái)實(shí)現(xiàn)負(fù)載均衡和失效轉(zhuǎn)移功能。在J2EE中,分布式技術(shù)包括:JSP(Servlet),JDBC ,EJB,JNDI,JMS,Webservices和其他。當(dāng)分布式方法被調(diào)用時(shí)可以發(fā)生負(fù)載均衡和失效轉(zhuǎn)移。下面我們會(huì)討論細(xì)節(jié)。
4 web層集群實(shí)現(xiàn)
web層集群是J2EE集群中最重要和基礎(chǔ)的功能。web層集群技術(shù)包括:Web負(fù)載均衡和HTTPSession失效轉(zhuǎn)移。
4.1 web負(fù)載均衡
J2EE提供商有很多方法實(shí)現(xiàn)web負(fù)載均衡,基本的,在瀏覽器和web服務(wù)器之間放置負(fù)載均衡器。

圖5:web負(fù)載均衡
負(fù)載均衡器可以是硬件產(chǎn)品如F5 負(fù)載均衡器,也可以是另一個(gè)帶有負(fù)載均衡插件的web服務(wù)器。簡(jiǎn)單的帶有ipchains的linux box也可以執(zhí)行負(fù)載均衡的功能。無(wú)論何種技術(shù),負(fù)載均衡器通常有以下特性:
*實(shí)現(xiàn)負(fù)載均衡算法
當(dāng)客戶端請(qǐng)求達(dá)到時(shí),負(fù)載均衡器決定如何分發(fā)請(qǐng)求到后端服務(wù)器實(shí)例。通常的算法包括Round-Robin,(指的是使組中所有成員都能均等地以某種合理 的順序被選擇到的一種安排方式, 通常是從列表的頭至尾,而后周而復(fù)始),隨機(jī)和基于權(quán)重。 負(fù)載均衡器試圖使每個(gè)服務(wù)器實(shí)例完成相同的工作量,但以上算法都不能真正達(dá)到理想的等量,因?yàn)樗麄冎皇腔诜职l(fā)到某個(gè)服務(wù)器實(shí)例請(qǐng)求的數(shù)量來(lái)計(jì)算。一些聰 明的負(fù)載均衡器實(shí)現(xiàn)特別的算法,他們會(huì)測(cè)試每個(gè)服務(wù)器的工作負(fù)載來(lái)決定分發(fā)請(qǐng)求。
*心跳檢測(cè)
當(dāng)一些服務(wù)器實(shí)例失效時(shí),負(fù)載均衡器應(yīng)該檢測(cè)到失效,并不再分發(fā)請(qǐng)求到失效的服務(wù)器上。負(fù)載均衡器也需要監(jiān)視服務(wù)器恢復(fù)狀況,并給它重新分發(fā)請(qǐng)求。
*會(huì)話粘連
幾乎每個(gè)web應(yīng)用都有會(huì)話狀態(tài),使得記住用戶是否登陸或購(gòu)物車變得非常簡(jiǎn)單。因?yàn)镠TTP協(xié)議本身沒有狀態(tài),會(huì)話狀態(tài)需要存在某個(gè)地方,并和瀏覽會(huì)話關(guān) 聯(lián)起來(lái),可以在下一次請(qǐng)求時(shí)很容易地被檢索到。當(dāng)負(fù)載均衡時(shí),最好選擇分發(fā)相同的瀏覽器會(huì)話請(qǐng)求到同一臺(tái)服務(wù)器實(shí)例上,否則應(yīng)用工作會(huì)不正常。
因?yàn)闀?huì)話狀態(tài)存儲(chǔ)在某個(gè)web服務(wù)器實(shí)例的內(nèi)存中,“會(huì)話粘連”對(duì)于負(fù)載均衡非常重要。但,如果一臺(tái)服務(wù)器實(shí)例因?yàn)槟承┰蚴Вū热鐢嚯姡敲丛摲?wù) 器上多有的會(huì)話狀態(tài)就丟失了。負(fù)載均衡器檢測(cè)到了該失效,不再向其分發(fā)請(qǐng)求。但存儲(chǔ)在失效服務(wù)器上的會(huì)話的那些請(qǐng)求將丟失會(huì)話信息,這種情況會(huì)引起錯(cuò)誤, 因此會(huì)話失效轉(zhuǎn)移到來(lái)了!
4.2 HTTPSession失效轉(zhuǎn)移
幾乎所有的流行的J2EE提供商都在他們的集群產(chǎn)品中實(shí)現(xiàn)了HTTPSession失效轉(zhuǎn)移,確保所有的客戶請(qǐng)求可以不因?yàn)橐恍┓?wù)器實(shí)例的失效而丟失任 何會(huì)話狀態(tài)。如圖6所示,當(dāng)瀏覽器訪問(wèn)一個(gè)有狀態(tài)的web應(yīng)用(第1,2步),此應(yīng)用可以在內(nèi)存中創(chuàng)建會(huì)話對(duì)象存儲(chǔ)信息以備后用。同時(shí),向?yàn)g覽器送回 HTTPSession ID,用來(lái)標(biāo)記該會(huì)話對(duì)象(第3步)。瀏覽器以cookie的方式存儲(chǔ)該ID,并會(huì)在下次發(fā)起請(qǐng)求時(shí)送回web服務(wù)器。為了支持會(huì)話失效轉(zhuǎn)移,會(huì)話對(duì)象將 在某時(shí)某處將它自己備份(第4步)。負(fù)載均衡器可以檢測(cè)失效(第5,6步),分發(fā)請(qǐng)求到其他服務(wù)器實(shí)例(第7步)。因?yàn)闀?huì)話對(duì)象已經(jīng)被備份,新的web服 務(wù)器實(shí)例可以恢復(fù)該會(huì)話并正確地處理請(qǐng)求。

圖6:HTTPSession失效轉(zhuǎn)移
為了實(shí)現(xiàn)以上功能,注意下列問(wèn)題:
*全局HTTPSession ID
如上所述,HTTPSession ID用來(lái)標(biāo)記某個(gè)服務(wù)器實(shí)例內(nèi)存中的會(huì)話對(duì)象。在J2EE中,HTTPSession ID依賴于JVM實(shí)例。每個(gè)JVM實(shí)例可以控制多個(gè)web應(yīng)用,每個(gè)應(yīng)用又可以控制許多不同用戶的HTTPSession,HTTPSession ID是存取當(dāng)前JVM實(shí)例中相關(guān)會(huì)話對(duì)象的鍵。在會(huì)話失效轉(zhuǎn)移實(shí)現(xiàn)中,要求不同的JVM實(shí)例不應(yīng)該產(chǎn)生兩個(gè)同樣的HTTPSession ID,因?yàn)槭r(shí),在一個(gè)JVM的會(huì)話可能在另一個(gè)JVM中備份和恢復(fù)。所以,應(yīng)該建立全局的HTTPSession ID機(jī)制。
*如何備份會(huì)話狀態(tài)
如何備份會(huì)話狀態(tài)是一個(gè)使得J2EE服務(wù)器與眾不同的關(guān)鍵因素。不同的提供商實(shí)現(xiàn)不同。
*備份頻率和粒度
HTTPSession狀態(tài)備份有性能消耗,包括CPU周期,網(wǎng)絡(luò)帶寬和寫磁盤和數(shù)據(jù)庫(kù)的IO消耗。備份頻率和粒度嚴(yán)重影響集群的性能。
4.3 數(shù)據(jù)庫(kù)持久化方案
幾乎所有的J2EE集群產(chǎn)品允許你通過(guò)JDBC接口使用關(guān)系數(shù)據(jù)庫(kù)備份會(huì)話狀態(tài)。如圖7所示,該方案只是簡(jiǎn)單地讓服務(wù)器實(shí)例序列化會(huì)話內(nèi)容,并在適當(dāng)?shù)臅r(shí) 候?qū)懭霐?shù)據(jù)庫(kù)。當(dāng)失效轉(zhuǎn)移發(fā)生時(shí),另一個(gè)可用的服務(wù)器實(shí)例負(fù)責(zé)失效的服務(wù)器,并從數(shù)據(jù)庫(kù)中恢復(fù)會(huì)話狀態(tài)。 對(duì)象序列化是關(guān)鍵點(diǎn),使得內(nèi)存會(huì)話對(duì)象數(shù)據(jù)持久化和可移動(dòng)。更多對(duì)象序列化信息請(qǐng)參考
http://java.sun.com/j2se/1.5.0/docs/guide/serialization/index.html

圖7:備份會(huì)話狀態(tài)到數(shù)據(jù)庫(kù)
象數(shù)據(jù)庫(kù)事務(wù)一樣代價(jià)昂貴,該方案的主要缺點(diǎn)是有限的伸縮性:當(dāng)存儲(chǔ)大量會(huì)話中的對(duì)象時(shí)。許多使用數(shù)據(jù)庫(kù)會(huì)話持久化的應(yīng)用服務(wù)器鼓吹 HTTPSession的最小限度的使用,但其實(shí)他們還限制了你的應(yīng)用架構(gòu)和設(shè)計(jì),特別是如果你使用HTTPSession存儲(chǔ)緩沖用戶數(shù)據(jù)。
數(shù)據(jù)庫(kù)方案也有一些優(yōu)點(diǎn).
*實(shí)現(xiàn)簡(jiǎn)單。江會(huì)話備份處理和請(qǐng)求處理分離,使得集群易于管理并比較健壯。
*會(huì)話可以失效轉(zhuǎn)移到任何其它機(jī)器上,因?yàn)槭褂霉蚕頂?shù)據(jù)庫(kù)。
*會(huì)話數(shù)據(jù)可以在整個(gè)集群失效后仍然生存。
4.4 內(nèi)存復(fù)制方案
由于性能問(wèn)題,一些J2EE服務(wù)器(Tomcat,JBoss,WebLogic和WebSphere)提供另一種實(shí)現(xiàn):內(nèi)存復(fù)制。

圖8:內(nèi)存復(fù)制
基于內(nèi)存的會(huì)話持久化存儲(chǔ)會(huì)話信息,該方案由于性能好非常流行。和數(shù)據(jù)庫(kù)方案比較,在原始服務(wù)器和備份服務(wù)器之間直接網(wǎng)絡(luò)通信是非常輕量級(jí)的。請(qǐng)注意該方案,數(shù)據(jù)庫(kù)方案中的“恢復(fù)”階段是不需要的。請(qǐng)求到來(lái)時(shí),所有的會(huì)話數(shù)據(jù)已經(jīng)存在于備份服務(wù)器的內(nèi)存中了。
”JavaGroups”是目前JBoss和Tomcat集群的通訊層,JavaGroups 是一個(gè)實(shí)現(xiàn)群通訊和管理的工具包。它提供的核心特性是“Group membership protocols”和“message multicast”更多信息請(qǐng)參考http://www.jgroups.org/javagroupsnew/docs/index.html
4.4.1 Tomcat方案:多機(jī)復(fù)制
內(nèi)存復(fù)制存在很多變體方案。一中辦法是跨集群中的多節(jié)點(diǎn)復(fù)制會(huì)話狀態(tài)。Tomcat5以此法實(shí)現(xiàn)內(nèi)存復(fù)制。

圖9:多機(jī)復(fù)制
如圖9所示,當(dāng)一個(gè)服務(wù)器實(shí)例的會(huì)話狀態(tài)改變時(shí),它將向集群中所有服務(wù)器備份它的數(shù)據(jù)。如果其中一個(gè)實(shí)例失效,負(fù)載均衡器可選擇其它任何可用的服務(wù)器實(shí)例 作為其備份服務(wù)器。但該方案在伸縮性上有缺陷。如果集群中有很多實(shí)例,網(wǎng)絡(luò)通訊消耗就不可忽略了,這種情況將嚴(yán)重降低性能和網(wǎng)絡(luò)交通,成為瓶頸問(wèn)題。
4.4.2 Weblogic, Jboss and WebSphere的方案--配對(duì)復(fù)制
因?yàn)樾阅芎蜕炜s性問(wèn)題,Weblogic, JBoss and Websphere 都提供了另一種方法實(shí)現(xiàn)內(nèi)存復(fù)制:每個(gè)服務(wù)器實(shí)例選擇任一個(gè)備份實(shí)例存儲(chǔ)會(huì)話信息,如圖10。
按這種方式,每個(gè)服務(wù)器實(shí)例擁有它自己的配對(duì)備份服務(wù)器而不是所有其它服務(wù)器。該方案消除了伸縮性問(wèn)題。

圖10:配對(duì)復(fù)制
雖然該方案實(shí)現(xiàn)了會(huì)話失效轉(zhuǎn)移的高性能和高伸縮性,仍然有下列限制:
*給負(fù)載均衡器帶來(lái)了復(fù)雜性。當(dāng)一臺(tái)服務(wù)器實(shí)例失效,負(fù)載均衡器必須記住哪個(gè)實(shí)例是其配對(duì)備份服務(wù)器,縮小了負(fù)載均衡器 的選擇范圍,一些硬件均衡器不能在此結(jié)構(gòu)中使用。
* 除了處理正常的請(qǐng)求,服務(wù)器同時(shí)負(fù)責(zé)復(fù)制。每個(gè)服務(wù)器實(shí)例,請(qǐng)求處理容量被減小,因?yàn)镃PU周期需要完成復(fù)制職責(zé)。
*除了正常處理,許多內(nèi)存被用來(lái)存儲(chǔ)備份會(huì)話狀態(tài),即使沒有失效轉(zhuǎn)移發(fā)生,也增加了JVM垃圾收集的消耗。
*集群中的服務(wù)器實(shí)例組成復(fù)制配對(duì)。所以如果會(huì)話粘連失效的主服務(wù)器,負(fù)載均衡器能發(fā)送失效轉(zhuǎn)移請(qǐng)求到備份服務(wù)器上。備份服務(wù)器將在進(jìn)入的請(qǐng)求中遇到麻煩,引起性能問(wèn)題。
為了克服以上限制,不同的提供商的變種產(chǎn)生了。Weblogic 為每個(gè)會(huì)話而不是服務(wù)器定義了備份配對(duì)。當(dāng)一臺(tái)服務(wù)器實(shí)例失效,失效服務(wù)器上的會(huì)話被分散到不同備份服務(wù)器上,并且被分散地裝載。
4.4.4 IBM的方案--中央狀態(tài)服務(wù)器
Websphere 另一個(gè)可用的內(nèi)存復(fù)制選擇是:備份會(huì)話信息到一個(gè)中央狀態(tài)服務(wù)器,如圖11。

圖11:中央服務(wù)器復(fù)制
和數(shù)據(jù)庫(kù)方案非常相似,不同的是一個(gè)專門的“會(huì)話備份服務(wù)器”代替了數(shù)據(jù)庫(kù)服務(wù)器。該方案兼有數(shù)據(jù)庫(kù)和內(nèi)存復(fù)制的優(yōu)點(diǎn):
*分離的請(qǐng)求處理和會(huì)話備份,使得集群更強(qiáng)壯。
*所有的會(huì)話數(shù)據(jù)備份到專門的服務(wù)器上。bu需要服務(wù)器實(shí)例浪費(fèi)內(nèi)存區(qū)保存其它服務(wù)器的備份會(huì)話數(shù)據(jù)。
*會(huì)話可以失效轉(zhuǎn)移到其它任何實(shí)例上。因?yàn)闀?huì)話備份服務(wù)器是被集群中的所有節(jié)點(diǎn)共享的。所以,大多數(shù)負(fù)載均衡軟件和硬件可以在此集群中使用。更重要的是,請(qǐng)求裝載在失效時(shí)將均勻分散。
*因?yàn)閼?yīng)用服務(wù)器和會(huì)話備份服務(wù)器之間的socket通訊是輕量級(jí)的相對(duì)于重型的數(shù)據(jù)庫(kù)聯(lián)接。它比數(shù)據(jù)庫(kù)方案有著更好的性能和伸縮性。
然而,由于“恢復(fù)”階段覆蓋失效服務(wù)器的會(huì)話數(shù)據(jù),它的性能和直接或配對(duì)內(nèi)存復(fù)制方案不一樣,附加的會(huì)話備份服務(wù)器對(duì)管理員也增加了復(fù)雜性,性能瓶頸由備份服務(wù)器自己的性能所限制。
4.4.5 Sun的方案--特殊的數(shù)據(jù)庫(kù)

Sun 自己的方案,本節(jié)略,大家感興趣可以自己看原文。
4.4.6 其它失效轉(zhuǎn)移實(shí)現(xiàn)
JRun 使用Jini,Tangosol 使用分布式緩沖。本節(jié)無(wú)實(shí)質(zhì)內(nèi)容,略。
5 JNDI集群實(shí)現(xiàn)
暫略。
6 EJB 集群實(shí)現(xiàn)
暫略。
7 關(guān)于J2EE集群的神話
7.1 失效轉(zhuǎn)移可以完全避免錯(cuò)誤。 ---否定
JBoss文檔中,有一整章節(jié)警告“你真的需要HTTP會(huì)話復(fù)制嗎?”,是的,有時(shí)候一個(gè)沒有失效轉(zhuǎn)移的高可用性方案也是可以接受的,并且便宜。更進(jìn)一步說(shuō),失效轉(zhuǎn)移并不像你想的那樣有力。
到底失效轉(zhuǎn)移給了你什么?你們中的一些可能認(rèn)為它可以避免錯(cuò)誤。您瞧,沒有失效轉(zhuǎn)移,會(huì)話數(shù)據(jù)在服務(wù)器失效時(shí)丟失了并引起錯(cuò)誤;當(dāng)會(huì)話失效轉(zhuǎn)移,會(huì)話可以從備份中恢復(fù),并且請(qǐng)求可以由另一個(gè)實(shí)例繼續(xù)處理,客戶端不知道該失效。這可能是真的,但它不是必要的條件。
當(dāng)我定義“失效轉(zhuǎn)移”時(shí),我定義了失效轉(zhuǎn)移發(fā)生的條件:“在方法調(diào)用之間”,意味著你可以有兩個(gè)連續(xù)的到一個(gè)遠(yuǎn)程對(duì)象的方法,失效轉(zhuǎn)移將發(fā)生在第一個(gè)方法成功完成之后和第二個(gè)方法請(qǐng)求發(fā)出之前。
那么,在方法調(diào)用處理中間,遠(yuǎn)程服務(wù)器失效了會(huì)發(fā)生什么事情?答案是:處理將停止,大多數(shù)案例中,客戶端將看到錯(cuò)誤信息,除非該方法是等冪的(參考前文)。如果是等冪方法,一些負(fù)載均衡器足夠聰明,會(huì)在其它服務(wù)器上重試這些方法。
為什么等冪重要?因?yàn)楫?dāng)失效發(fā)生時(shí),客戶端從來(lái)不知道請(qǐng)求在哪里執(zhí)行,方法被初始化或已經(jīng)完成了?客戶端從不確定它。如果方法不是等冪的,兩次調(diào)用同樣的方法將改變系統(tǒng)狀態(tài)兩次,系統(tǒng)將處于不一致狀態(tài)。
您可能想把所有的方法放在一個(gè)事務(wù)中就變成等冪的了。畢竟,如果錯(cuò)誤發(fā)生,事務(wù)將回滾,所有的事務(wù)狀態(tài)沒有改變。但是事實(shí)是,事務(wù)邊界不能包括所有遠(yuǎn)程方法調(diào)用。如果事務(wù)提交,在返回客戶端時(shí)網(wǎng)絡(luò)崩潰,客戶端不會(huì)知道服務(wù)器事務(wù)成功與否。
在應(yīng)用中,將所有方法變成等冪是不可能的。所以,通過(guò)失效轉(zhuǎn)移,你可以減少錯(cuò)誤,但不能避免它們!以再現(xiàn)購(gòu)物網(wǎng)站為例,假定每臺(tái)服務(wù)器實(shí)例可以同時(shí)處理 100個(gè)在線用戶的請(qǐng)求。當(dāng)一臺(tái)服務(wù)器失效,沒有會(huì)話失效轉(zhuǎn)移的方案將丟失所有那100個(gè)用戶的會(huì)話數(shù)據(jù)并激怒他們;當(dāng)擁有會(huì)話失效轉(zhuǎn)移,只有20個(gè)用戶 的請(qǐng)求被失效的服務(wù)器在處理過(guò)程中,只有這些用戶被錯(cuò)誤激怒了。其它80個(gè)用戶還處在思考時(shí)間(用戶行為的間隔時(shí)間)或者方法調(diào)用之間。這些用戶的會(huì)話被 透明地失效轉(zhuǎn)移了。所以,你應(yīng)該考慮以下事項(xiàng):
*激怒20個(gè)和100個(gè)用戶的不同影響
*擁有失效轉(zhuǎn)移和沒有失效轉(zhuǎn)移的成本
7.2 單機(jī)應(yīng)用可以被透明地轉(zhuǎn)換為集群結(jié)構(gòu) ---- 絕對(duì)不是!
雖然一些提供商聲稱他們的J2EE產(chǎn)品的適應(yīng)性,不要相信他們!實(shí)際上,你應(yīng)該在系統(tǒng)設(shè)計(jì)開始時(shí)就考慮集群,并影響到開發(fā)和測(cè)試的所有階段。
7.2.1 Http會(huì)話
在集群環(huán)境,對(duì)HTTPSession的使用有著嚴(yán)格的限制正如我在前邊提及的一樣,你的應(yīng)用服務(wù)器依賴不同的機(jī)制使用會(huì)話失效轉(zhuǎn)移。最重要的限制是所有 存儲(chǔ)在HTTPSession里的對(duì)象必須是可序列化的,這一點(diǎn)限制了應(yīng)用的結(jié)構(gòu)和設(shè)計(jì)。一些設(shè)計(jì)模式和MVC框架使用HTTPSession存儲(chǔ)不可序 列化對(duì)象(如Servlet Context,Local EJB 接口,web services引用),這樣的設(shè)計(jì)不能在集群中工作。其次,對(duì)象序列化和反序列化在性能上消耗很大特別是數(shù)據(jù)庫(kù)方案。在這樣的環(huán)境中,存儲(chǔ)巨大或眾多的 會(huì)話對(duì)象,應(yīng)該避免。如果你已經(jīng)選擇內(nèi)存復(fù)制方案,小心HTTPSession的交叉引用屬性的限制。另一主要的區(qū)別是,你需要在每次改變 HTTPSession屬性的時(shí)候調(diào)用“setAttribute ()”方法。調(diào)用這些方法在單機(jī)應(yīng)用中不是必須的。其目的是將改變的屬性和未改變的屬性分離開來(lái),所以系統(tǒng)可以只備份必要的數(shù)據(jù)。
7.2.2 緩沖
幾乎我經(jīng)歷過(guò)的每一個(gè)J2EE項(xiàng)目都使用緩沖提升性能,所有的流行服務(wù)器提供不同程度的緩沖以提升應(yīng)用性能。但這些緩沖是單機(jī)應(yīng)用的典型設(shè)計(jì),只能在一個(gè) JVM實(shí)例上工作。我們需要緩沖是因?yàn)閯?chuàng)建這些新對(duì)象的代價(jià)是如此昂貴,所以我們維護(hù)一個(gè)對(duì)象池來(lái)重用對(duì)象實(shí)例。每個(gè)JVM實(shí)例都擁有自己的緩沖拷貝,它 們也應(yīng)該被同步,以在所有服務(wù)器實(shí)例上維持一致的狀態(tài)。有時(shí),這種同步導(dǎo)致性能惡劣還不如不要緩沖。
7.7.3 靜態(tài)變量
一些設(shè)計(jì)模式,比如“Singleton”(單例) 使用靜態(tài)變量來(lái)給其它對(duì)象共享狀態(tài)。這種方案在單一的服務(wù)器上工作得很好,但在集群中失效了。集群中的每個(gè)實(shí)例都會(huì)在其JVM實(shí)例中維護(hù)它自己的靜態(tài)變量 拷貝,因此就破壞了該設(shè)計(jì)模式的共享機(jī)制。一個(gè)使用靜態(tài)變量的例子是保持在線用戶的總數(shù)。簡(jiǎn)單的辦法就是將改數(shù)字存儲(chǔ)到靜態(tài)變量中,當(dāng)用戶登錄或下線時(shí)增 加或減少它。在單一服務(wù)器上該應(yīng)用絕對(duì)運(yùn)行得非常好,但在集群中就失效了。更可取的辦法是將所有狀態(tài)存儲(chǔ)到數(shù)據(jù)庫(kù)中去。
7.7.4 外部資源
雖然J2EE規(guī)范不推薦使用,外部I/O操作還是有很多的用途。例如一些應(yīng)用使用文件系統(tǒng)存儲(chǔ)用戶上載的文件,或者創(chuàng)建動(dòng)態(tài)的配置XML文件。在集群中, 英勇服務(wù)器沒法跨實(shí)例復(fù)制這些文件。為了在集群中工作,解決方案是如有可能,使用數(shù)據(jù)庫(kù)替代外部文件。也可以選擇SAN作為中央文件存儲(chǔ)。(備注:SAN 英文全稱:Storage Area Network,即存儲(chǔ)區(qū)域網(wǎng)絡(luò)。它是一種通過(guò)光纖集線器、光纖路由器、光纖交換機(jī)等連接設(shè)備將磁盤陣列、磁帶等存儲(chǔ)設(shè)備與相關(guān)服務(wù)器連接起來(lái)的高速專用 子網(wǎng)。)
7.7.5 特殊的服務(wù)
有一些特殊的服務(wù)只有在單機(jī)模式下才有意義。定時(shí)器服務(wù)就是一種,給予一個(gè)恒定的間隔有規(guī)律地發(fā)生。定時(shí)器服務(wù)通常用來(lái)自動(dòng)執(zhí)行管理任務(wù),比如日志文件轉(zhuǎn) 儲(chǔ),系統(tǒng)數(shù)據(jù)備份,數(shù)據(jù)庫(kù)consistence 檢測(cè)和冗余數(shù)據(jù)清除。一些基于事件的服務(wù)也很難移植到集群環(huán)境中。初始化服務(wù)就是很好的例子。郵件通知服務(wù)也是如此。
這些服務(wù)由事件而非請(qǐng)求觸發(fā),應(yīng)當(dāng)只執(zhí)行一次。這樣的服務(wù)將使得集群的負(fù)載均衡和失效轉(zhuǎn)移的意義降低。
一些產(chǎn)品對(duì)這樣的服務(wù)早有準(zhǔn)備,例如,JBoss使用“集群?jiǎn)我辉O(shè)施”協(xié)調(diào)所有實(shí)例,保證只執(zhí)行這些服務(wù)一次或僅僅一次。基于你選擇的產(chǎn)品平臺(tái),這些服務(wù)有可能成為移植到集群的障礙。
7.8 分布式結(jié)構(gòu)比排列式結(jié)構(gòu)更有彈性? -- 不一定!
J2EE技術(shù),特別是EJB,因?yàn)榉植际接?jì)算而產(chǎn)生。解耦業(yè)務(wù)功能,重用遠(yuǎn)程對(duì)象使得多層應(yīng)用流行。但我們也不能把所有東西都分布式化吧。一些J2EE架構(gòu)師認(rèn)為將web層和EJB層緊密排列更好。

圖20:分布式結(jié)構(gòu)
如圖20分布式結(jié)構(gòu),當(dāng)請(qǐng)求到來(lái)時(shí),負(fù)載均衡器將它們分發(fā)到不同的服務(wù)器上的web容器,如請(qǐng)求中包括EJB調(diào)用,web容器將重新分發(fā)EJB調(diào)用到布通的EJB容器。這樣,請(qǐng)求被負(fù)載均衡和失效轉(zhuǎn)移了兩次。
一些人不看好分布式結(jié)構(gòu),他們指出:
*第二次負(fù)載均衡是不必要的,因?yàn)樗荒苁谷蝿?wù)分配更均勻。每個(gè)服務(wù)器實(shí)例在同一個(gè)JVM實(shí)例中都擁有它自己的web容器和EJB容器。讓EJB容器處理其它實(shí)例的web容器的請(qǐng)求,看不出比實(shí)例內(nèi)部調(diào)用有更多的優(yōu)點(diǎn)。
*第二次失效轉(zhuǎn)移是不必要的,因?yàn)樗⒉辉黾涌捎眯浴6鄶?shù)提供商的產(chǎn)品都是在同一JVM實(shí)例中集成了web容器和EJB容器。如果EJB容器失效,在多數(shù)情況下,web容器此時(shí)也是失效的。
*性能降低了。設(shè)想應(yīng)用中的一個(gè)方法將調(diào)用幾個(gè)EJB,若對(duì)每個(gè)EJB進(jìn)行負(fù)載均衡,最終應(yīng)用實(shí)例跨越了很多的服務(wù)器實(shí)例運(yùn)行。這些服務(wù)器對(duì)服務(wù)器的橫跨通信是不必要的。還有,如果方法在一個(gè)事務(wù)中,事務(wù)邊界將包括許多服務(wù)器實(shí)例,嚴(yán)重影響了性能。
在實(shí)際的運(yùn)行狀態(tài),多數(shù)提供商(包括Sun JES, Weblogic and JBoss)優(yōu)化了EJB負(fù)載均衡使得請(qǐng)求首先選擇在同一個(gè)服務(wù)器中的EJB容器。用這種辦法,只在web層進(jìn)行負(fù)載均衡,后續(xù)的服務(wù)都在同一服務(wù)器上處 理。這種結(jié)構(gòu)稱為排列式結(jié)構(gòu)。技術(shù)上說(shuō),也是分布式結(jié)構(gòu)的一種。

圖2:排列式結(jié)構(gòu)
一個(gè)有趣的問(wèn)題是,因?yàn)榇蟛糠职l(fā)布運(yùn)行時(shí)最后都成為了排列式結(jié)構(gòu),為什么不直接使用本地接口代替遠(yuǎn)程接口,這將提升性能。當(dāng)然可以這樣。但請(qǐng)記住,使用本 地接口,web組件和EJB就緊密耦合了,使得方法直接調(diào)用而非通過(guò)IIOP/RMI。負(fù)載均衡器和失效轉(zhuǎn)移分發(fā)器沒有機(jī)會(huì)攔截本地調(diào)用,“Web+ EJB”過(guò)程就被作為一個(gè)整體了。
不幸的是,集群中,在J2EE服務(wù)器上使用本地接口有很多限制。EJB是帶有本地接口的本地對(duì)象,但他們不可序列化。限制就是本地引用不允許存儲(chǔ)在 HTTPSession中。一些產(chǎn)品,如Sun JES區(qū)別處理本地EJB,使他們可序列化也能存儲(chǔ)在HTTPSession中。
另一個(gè)有趣的問(wèn)題是:因?yàn)榕帕惺浇Y(jié)構(gòu)很流行也有良好的性能,為什么還需要分布式結(jié)構(gòu)?大多蘇h情況,事出有因,有時(shí)分布式結(jié)構(gòu)不可替代。
*EJB不僅僅給web容器使用,富客戶端也是用戶之一。
*EJB組件和web組件可能在不同的安全級(jí)別,需要物理地分隔開來(lái)。所以,防火墻可能用來(lái)保護(hù)運(yùn)行EJB的更重要的機(jī)器。
*Web層和EJB層的極端不對(duì)稱也許是選擇分布式結(jié)構(gòu)的一個(gè)好理由,例如,一些EJB組件太復(fù)雜資源消耗巨大,那么它們只能在一些昂貴的 大服務(wù)器上運(yùn)行;另一方面,web組件(HTML,JSP,Servlet)非常簡(jiǎn)單可以在便宜的PC服務(wù)器上運(yùn)行。在這種條件下,專門的web服務(wù)器接 收客戶端請(qǐng)求,提供靜態(tài)數(shù)據(jù)(HTML和圖片)和簡(jiǎn)單的web組件(JSP和Servlet)。大型服務(wù)器只用來(lái)進(jìn)行復(fù)雜計(jì)算。
8 結(jié)論
集群和單機(jī)環(huán)境是不同的。J2EE提供商以不同的方式實(shí)現(xiàn)集群。為了構(gòu)建一個(gè)大型的系統(tǒng),在項(xiàng)目開始時(shí),你就應(yīng)該為J2EE集群做準(zhǔn)備。選擇合適的 J2EE產(chǎn)品是g和你的應(yīng)用。選擇合適的第三方軟件和框架時(shí)確保它們可以被集群。然后設(shè)計(jì)合適的架構(gòu)以得到集群帶來(lái)的實(shí)際利益。
概述
一個(gè)集群系統(tǒng)是一群松散結(jié)合的服務(wù)器組,形成一個(gè)虛擬的服務(wù)器,為客戶端用戶提供統(tǒng)一的服務(wù)。對(duì)于這個(gè)客戶端來(lái)說(shuō),通常在訪問(wèn)集群系統(tǒng)時(shí)不會(huì)意識(shí)到它的服務(wù)是由具體的哪一臺(tái)服務(wù)器提供。集群系統(tǒng)一般應(yīng)具高可用性、可伸縮性、負(fù)載均衡、故障恢復(fù)和可維護(hù)性等特殊性能。越來(lái)越多的關(guān)鍵任務(wù)和大型應(yīng)用正運(yùn)行在J2EE平臺(tái)上,象銀行之類的應(yīng)用要求很高的可用性(HA),大型系統(tǒng)比如大型網(wǎng)站則要求更好的伸縮性。J2EE集群是最常用的技術(shù),用來(lái)提供高可用性和伸縮性的容錯(cuò)服務(wù),單機(jī)部署和多機(jī)集群化部署差別很大,網(wǎng)上的資料大多語(yǔ)焉不詳,即使文檔圖文并茂,也是到了關(guān)鍵處就部署成功,其實(shí)后面還要做些工作才行,且多以單機(jī)部署多個(gè)server來(lái)模擬集群化部署,其實(shí)和真正多機(jī)部署還是有比較大的差別。本文僅以weblogic應(yīng)用服務(wù)器為例說(shuō)明集群化部署。
集群層次說(shuō)明
Web級(jí)集群,是J2EE集群中最重要和基礎(chǔ)的功能。web層集群技術(shù)包括:Web負(fù)載均衡和HTTPSession失效轉(zhuǎn)移。web負(fù)載均衡,基本的是在瀏覽器和web服務(wù)器之間放置負(fù)載均衡器。<o:p></o:p>
應(yīng)用級(jí)集群,是ejb集群,EJB是J2EE應(yīng)用平臺(tái)的核心,EJB是用于開發(fā)和部署具多層結(jié)構(gòu)的、分布式的、面向?qū)ο蟮腏ava應(yīng)用系統(tǒng)跨平臺(tái)的構(gòu)件體系結(jié)構(gòu)。主要是業(yè)務(wù)應(yīng)用,部署在EJB容器上。<o:p></o:p>
數(shù)據(jù)庫(kù)級(jí)集群,是oracle數(shù)據(jù)庫(kù)設(shè)置多個(gè)數(shù)據(jù)庫(kù)實(shí)例,全部映射到數(shù)據(jù)庫(kù)。
Weblogic集群概念
Ø Domain:由配置為Administrator Server的WebLogic Server實(shí)例管理的邏輯單元,這個(gè)單元是有所有相關(guān)資源的集合。
Ø Server: 一個(gè)相對(duì)獨(dú)立的,為實(shí)現(xiàn)某些特定功能而結(jié)合在一起的單元。按功能可分為domain server 和managed server。一個(gè)Domain 可以包含一個(gè)或多個(gè)WebLogic Server實(shí)例,甚至是Server集群。一個(gè)Domain中有一個(gè)且只能有一個(gè)Server 擔(dān)任管理Server的功能,其它的Server具體實(shí)現(xiàn)一個(gè)特定的邏輯功能。
Ø Domain Server:在一個(gè)集群中,有且僅有一個(gè)domain server,即管理server,該server只負(fù)責(zé)管理多個(gè)Managed server(被管理server),即domain server僅僅是行政領(lǐng)導(dǎo),考勤之類的活動(dòng),如某個(gè)managed Sever的狀態(tài),是未知(unKnown),還是運(yùn)行(run),還是停止(shutdown),遠(yuǎn)程啟動(dòng)等等,不負(fù)責(zé)具體業(yè)務(wù)。因此部署時(shí)domain server上不要部署具體任務(wù),畢竟人家是當(dāng)官的嗎。
Ø Managed Server:真正的實(shí)干家,部署具體的應(yīng)用。應(yīng)用及業(yè)務(wù)邏輯組件被分發(fā)在多個(gè)受管服務(wù)器(Managed Server)。<o:p></o:p>
Weblogic集群要求
Ø 集群中的所有Server必須位于同一網(wǎng)段,并且必須是IP廣播(UDP)可到達(dá)的
Ø 集群中的所有Server必須使用相同的版本,包括Service Pack
Ø 集群中的Server必須使用永久的靜態(tài)IP地址。動(dòng)態(tài)IP地址分配不能用于集群環(huán)境。如果服務(wù)器位于防火墻后面,而客戶機(jī)位于防火墻外面,那么服務(wù)器必須有公共的靜態(tài)IP地址,只有這樣,客戶端才能訪問(wèn)服務(wù)器 <o:p></o:p>
Ø 使用weblogic的支持集群的licence<o:p></o:p>
項(xiàng)目實(shí)戰(zhàn)
項(xiàng)目概況
我們的項(xiàng)目是struts—ejb—hibernate—spring,因?yàn)閔ibernate和spring都必須進(jìn)行初始化且初始化都依賴于servlet,在系統(tǒng)啟動(dòng)時(shí)就初始化數(shù)據(jù),并且我們?cè)趙eb層和ejb層分別部署為web集群和ejb集群,而hibernate和spring都部署在應(yīng)用服務(wù)器上。為此,我們打了兩個(gè)部署包,一個(gè)是cnlife.war, cnlife_app.ear,其中cnlife.war包部署在web集群上,cnlife
_app.ear部署在ejb集群上,cnlife_app.ear包括兩個(gè)包,其中一個(gè)是cnlifeejb.jar(ejb包),
另外一個(gè)是backgroudinit.war,backgroudinit.war用來(lái)初始化spring,hibernate的初始化數(shù)據(jù)。
<o:p> </o:p>
cnlife.war (部署在Web Server)
_backgroudinit.war
|
cnlife_app.ear-| (部署在 Application Server)
|_cnlifeejb.jar
<o:p> </o:p>
Ejb是stateless Session bean,使用ejb的目的就是應(yīng)用服務(wù)器集群,部署示意圖如下:
Web級(jí)集群
Web集群中使用內(nèi)存復(fù)制策略<o:p></o:p>
weblogic.xml 如下
<o:p></o:p>
8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd"><o:p></o:p>
<o:p> </o:p>
<weblogic-web-app><o:p></o:p></weblogic-web-app>
<session-descriptor><o:p></o:p></session-descriptor>
原文地址:http://hqman.iteye.com/blog/92684