越來越多的關(guān)鍵應(yīng)用運行在J2EE(Java 2, Enterprise Edition)中,這些諸如銀行系統(tǒng)和賬單處理系統(tǒng)需要高的可用性(High Availability, HA),同時像Google和Yahoo這種大系統(tǒng)需要大的伸縮性。高可用性和伸縮性在今天高速增長的互連接的世界的重要性已經(jīng)證實了。eBay于1999年6月停機(jī)22小時的事故,中斷了約230萬的拍賣,使eBay的股票下降了9.2個百分點。
J2EE集群是用來提供高可用性和伸縮性服務(wù),同時支持容錯處理的一種流行的技術(shù)。但是,由于J2EE規(guī)范缺乏對集群的支持,J2EE供應(yīng)商實現(xiàn)集群的方法也各異。這給J2EE架構(gòu)師和開發(fā)人員帶來了很多困難。以下是幾個常見的問題:
l 為什么帶集群功能的商業(yè)J2EE服務(wù)器產(chǎn)品如此昂貴?(10倍于不帶集群功能的產(chǎn)品)
l 為什么基于單服務(wù)器環(huán)境構(gòu)建的應(yīng)用不能在集群中運行?
l 為什么應(yīng)用在集群環(huán)境中運行得很慢,但在非集群環(huán)境中卻快得多?
l 為什么集群的應(yīng)用移植到其他服務(wù)器中失敗?
理解這些限制和要素的最佳方法是學(xué)習(xí)他們的實現(xiàn)方式。
基本術(shù)語
在我們討論不同的集群實現(xiàn)之前,先談?wù)剮讉€概念。這有助于理解不同的J2EE集群產(chǎn)品不同的設(shè)計結(jié)果和概念:
伸縮性(Scalability):
在一些大的系統(tǒng)中,預(yù)測最終用戶的數(shù)量和行為是非常困難的,伸縮性是指系統(tǒng)適應(yīng)不斷增長的用戶數(shù)的能力。提高這種并發(fā)會話能力的一種最直觀的方式就增加資源(CPU,內(nèi)存,硬盤等),集群是解決這個問題的另一種方式,它允許一組服務(wù)器組在一起,像單個服務(wù)器一樣分擔(dān)處理一個繁重的任務(wù)。
高可用性(High availability):
單一服務(wù)器的解決方案并不是一個健壯方式,因為容易出現(xiàn)單點失效。像銀行、賬單處理這樣一些關(guān)鍵的應(yīng)用程序是不能容忍哪怕是幾分鐘的死機(jī)。它們需要這樣一些服務(wù)在任何時間都可以訪問并在可預(yù)期的合理的時間周期內(nèi)有響應(yīng)。集群方案通過在集群中增加的冗余的服務(wù)器,使得在其中一臺服務(wù)器失效后仍能提供服務(wù),從而獲得高的可用性。
負(fù)載均衡(Load balancing):
負(fù)載均衡是集群的一項關(guān)鍵技術(shù),通過把請求分發(fā)給不同的服務(wù)器,從而獲得高可用性和較好的性能。一個負(fù)載均衡器可以是從一個簡單的Servlet或Plug-Ins(例如一個Linux box利用ipchains來實現(xiàn)),到昂貴的內(nèi)置SSL加速器的硬件。除此之外,負(fù)載均衡器還需執(zhí)行一些其他的重要任務(wù),如“會話膠粘”讓一個用戶會話始終存在一個服務(wù)器上,“健康檢查”用于防止將請求分發(fā)到已失效的服務(wù)器上。有些負(fù)載均衡器也會參與我們下面將要談到“失效轉(zhuǎn)移”過程。
容錯(Fault tolerance):
高可用性意味著對數(shù)據(jù)正確性的要求不那么高。在J2EE集群中,當(dāng)一個服務(wù)器實例失效后,服務(wù)仍然是有效的,這是因為新的請求將被冗余服務(wù)器處理。但是,當(dāng)一個請求在一個正在失效的服務(wù)器中處理時,可能得到不正確的結(jié)果。不管有多少個錯誤,容錯的服務(wù)應(yīng)當(dāng)能確保有嚴(yán)格的正確的行為。
失效轉(zhuǎn)移(Failover):
失效轉(zhuǎn)移是集群中用來獲取容錯能力的另一項關(guān)鍵的技術(shù)。當(dāng)一個結(jié)點失效后,通過選擇集群中的另一個結(jié)點,處理將會繼續(xù)而不會終止。轉(zhuǎn)移到另一個結(jié)點可以被顯式的編碼,或是通過底層平臺自動地透明地路由到另一個服務(wù)器。
等冪方法(Idempotent methods):
等冪方法是指這樣一些方法:重復(fù)用相同的參數(shù)調(diào)用都能得到相同的結(jié)果。這些方法不會影響系統(tǒng)狀態(tài),可以重復(fù)調(diào)用而不用擔(dān)心改變系統(tǒng)。例如:getUsername()就是等冪的,而deleteFile就不是。當(dāng)我們討論HTTP Session失效轉(zhuǎn)移和EJB失效轉(zhuǎn)移時,它是一個重要的概念。
什么是J2EE集群
一個天真的問題,不是嗎?但我仍要用幾句話和圖來回答它。通常,J2EE集群技術(shù)包括"負(fù)載均衡"和"失效轉(zhuǎn)移"。
圖 1 負(fù)載均衡
如圖1所示,負(fù)載均衡意味著有許多客戶端向目標(biāo)對象同時發(fā)出請求。負(fù)載均衡器在調(diào)用者和被調(diào)用者之間,分發(fā)請求到與原始對象相同的冗余對象中。伸縮性和高可用性就是這樣得到的。
圖 2 失效轉(zhuǎn)移
如圖2所示,失效轉(zhuǎn)移與負(fù)載均衡不同。有時客戶端會連續(xù)發(fā)請求到目標(biāo)對象,如果請求中間目標(biāo)對象失效了,失效轉(zhuǎn)移系統(tǒng)將檢測到這次失敗,并將請求重定向到另一個可用的對象。通過這種方式可以獲得容錯能力。
如果你想知道更多的有關(guān)J2EE集群的知識,你就會問到一個基本的問題,“什么對象可以集群?”和“在我的J2EE代碼中哪里會發(fā)生負(fù)載均衡和失效轉(zhuǎn)移呢?”。這些都是用來理解J2EE集群的非常好的問題。實際上,并不是所有的對象都能被集群的,并且負(fù)載均衡和失效轉(zhuǎn)移并不是在J2EE代碼所有地方都能發(fā)生。看看下面的例子代碼:
圖 3 例子代碼
在Class A的bussiness()方法中,instance1可以負(fù)載均衡嗎?或是當(dāng)其失效,可以失效轉(zhuǎn)移到其他B的實例上嗎?我想是不行的!對負(fù)載均衡和失效轉(zhuǎn)移來說,必須要有個攔截器在調(diào)用者和被調(diào)用者之間分發(fā)或重定向請求到不同的對象上。Class A和Class B的實例是運行在一個JVM中緊密耦合的,在方法調(diào)用間加入分發(fā)邏輯非常困難。
什么類型對象可以被集群?——只有那些可以被部署到分布式拓樸結(jié)構(gòu)中的組件。
在我的J2EE代碼中,什么地方會有負(fù)載均衡和失效轉(zhuǎn)移?——只在你調(diào)用分布式組件的方法時。
圖 4 分布式對象
在如圖4所示的分布式環(huán)境中,調(diào)用者和被調(diào)用者被分離在有明顯邊界的不同的運行容器中,這個邊界可以是JVM,進(jìn)程和機(jī)器。
當(dāng)目標(biāo)對象被客戶端調(diào)用時,目標(biāo)對象的功能是在容器中運行的(這就是為什么我們說它是分布式的原因)。客戶端和目標(biāo)對象通過標(biāo)準(zhǔn)的網(wǎng)絡(luò)協(xié)議通信。這些特性就為一些機(jī)制提供了機(jī)會可以介入到方法調(diào)用之間實現(xiàn)負(fù)載均衡和失效轉(zhuǎn)移。
如圖4,瀏覽器通過HTTP協(xié)議調(diào)用JSP對象,JSP運行在WEB服務(wù)器中,瀏覽器只需要返回結(jié)果而不關(guān)心它是怎么運行的。在上述場景中,一些東西就可以在瀏覽器與WEB服務(wù)器之間實現(xiàn)負(fù)載均衡和失效轉(zhuǎn)移的功能。在J2EE平臺,分布式技術(shù)包括:JSP(Servlet),JDBC,EJB,JNDI,JMS,WEB Service等。負(fù)載均衡和失效轉(zhuǎn)移就發(fā)生在這些分布式方法被調(diào)用時。在后續(xù)部分我們將詳細(xì)討論這些技術(shù)。