J2EE集羣原理(二)

 

JNDI集羣

Jndi集羣對於EJB也是非常重要的,因爲幾乎所有的EJB都是從JNDI調用開始的

 

共享全局JNDI

WeblogicJBOSS都使用一個全局的、共享的、分佈在整個集羣系統的JNDI樹,對象被綁定到全局上下文,使用ip多播方式拷貝JNDI數據

 

圖十四:全局共享JNDI

 

集羣中的每個節點都有自己的命名服務器,並且自動保存其他所有節點的JNDI數據,因此這種結構具有高度可靠性

實際中,集羣JNDI樹主要有兩個用途:一是用於部署,你只需要將某個EJB部署到一臺服務器上,系統會自動將其拷貝到其他節點。二是在運行中你可以用JNDI存取自己的對象,這些自定義對象同樣會被自動拷貝到其他節點。

 

獨立的JNDI

Sun JES, IBM Websphere和其他廠商使用的是獨立的JNDI樹,各個節點擁有自己獨立的JNDI,而不會關心其他節點的JNDI。但這並不意味着它們不能實現集羣,關鍵是每臺服務器上的配置要相同,應用也要相同,這樣的話通過代理agent就能實現高性能的集羣了

Sun JES IBM Websphere都在每個節點處安裝了一個agent,由console負責協調各個agent

但這種方式不支持動態綁定運行時生成的對象,設計者的理由是:JNDI本身就是作爲管理外部資源的中間層,運行時對象綁定不在JNDI的職責範圍內,如果真的有這種需要,可以使用LDAP或者具有HA功能的數據庫。SunIBM都有自己的LDAP實現

 

中央型JNDI

少數廠商採用中央型的JNDI,所有節點都去一個某個指定的JNDI服務器上獲取資源,當然這對於客戶端來說是透明的。不過這種方式會大大增加安裝和管理的複雜性,因此被大部分廠商放棄

 

怎樣開始連接JNDI

使用JNDI,你必須知道提供JNDI服務的域名或IP以及端口,在全局和獨立型JNDI樹中,都存在着多個JNDI服務器,客戶端要連接哪一個呢,負載均衡和失效備援又是如何實現的呢?

技術上來說,可以在客戶端和JNDI服務器之間放一個硬件或軟件實現的負載均衡器,來實現上述要求,不過大部分廠商都有更加簡單的方法:

l  SUN JES JBOSS 能夠令“java.naming.provider.url”這一JNDI屬性支持用逗號分隔多個地址,例如,“java.naming.provider.url=server1:1100,server2:1100,server3:1100,server4:1100”,客戶端會逐個搜索,直到找到一個可用的爲止

l  JBOSS還支持自動找尋功能,即令“java.naming.provider.url”屬性爲空,客戶端會自動以網絡多播的方式尋找一個JNDI服務器作爲查詢的起始點

 

EJB集羣原理

EJB衍生自分佈式計算技術,服務器組件或富客戶端都能夠以標準協議(RMI/IIOP)調用遠程的EJB,並且RMI/IIOP技術能夠屏蔽底層網絡,使得EJB的調用對客戶透明化

圖:EJB調用原理

如圖,客戶端不是直接和EJB打交道,而是通過stub來代理。Stub負責利用RMI找到遠程的EJB並進行調用。EJB的調用過程分爲下面三步(EJB2.0

l  JNDI中查找EJBHOME stub

l  利用home stub創建一個EJB Object stub

l  利用EJB Object stub調用EJB的方法

 

JNDI查找時,可以利用上文說到的方法進行負載均衡;各廠商也會有自己專門的技術對stub的使用進行負載均衡,一般有以下三種方式:

 

Smart stub

我們知道,stub可以通過JNDI來獲得和創建,甚至可以直接下載相應的class文件來在運行時動態生成,而無須在客戶端本地的classpath中聲明

 

圖十七:smart stub

 

如圖十七,Weblogic JBOSS通過在stub的代碼中嵌入特殊的代碼來實現集羣,這個stub的確相當smart,它包含了所有能夠訪問的集羣服務器節點、內置了專門的集羣算法來決定把請求發給何處,甚至當集羣的拓撲有變時(比如增加了節點),能動態改變自身來適應新的結構,無須手工干預

 

Smart stub有以下幾個好處:

l  節省大量服務器資源

l  由於負載均衡是由客戶端處理,因此可以防止在服務器端放置負載均衡器而可能導致的單點失敗

l  Stub可以動態下載安裝,意味着無須手工維護

 

IIOP Runtime Library

Sun JES採用另一種方法,它直接修改客戶端的IIOP運行時庫

 

圖十八:IIOP Runtime

 

如圖十八,sun直接把負載均衡邏輯轉移到了IIOP庫中,從而使stub能夠保持“小而輕”,同時由於IIOP是底層庫,能夠更加有效地獲取和使用JVM提供的資源。但正是由於底層庫有所不同,使得JES與其他J2EE服務器打交道時可能會出現一些問題

 

 

Interceptor Proxy

IBM Websphere使用Location Service Daemon (LSD)作爲一個攔截器代理來實現EJB集羣

 

 

 

Figure 19: Interceptor Proxy

 

使用這種機制,stub中包含至LSD的路由信息,而不是直接去找服務器節點,這樣LSD就能獲得所有請求並進行負載均衡了,不過這樣會大大增加管理和維護的成本

 

 

EJB的集羣支持

調用EJB方法的過程中我們要和兩個stub打交道,一個是home stub,另一個是object stub,因此可以在兩個層面上實現負載均衡和失效備援

 

EJBHOME STUB的集羣實現

由於EJBHOME STUB本身不包括任何客戶端信息,無論從哪個服務器上獲得的EJBHOME STUB都是一樣的,因此當客戶端調用EJBHOME STUBcreate等方法時,就能利用一些負載均衡的算法選擇合適的服務器節點

 

EJBOBJECT STUB的集羣實現

EJBOBJECT STUB包含業務接口,而且其本身也能夠含有集羣節點的信息,但也不是所有的方法調用都能夠進行負載均衡式的路由,得看EJB的類型是什麼

 

l  無狀態會話bean最容易實現負載均衡了,因爲它本身不包含特定的客戶信息

l  有狀態會話bean略有不同,因爲它本身包含客戶端的會話信息,因此有狀態bean的集羣實現本質上和HTTP session 無異,一般情況下客戶端的stub都是一直與某個節點上的EJB組件打交道的,除非中途出問題了纔會將請求轉發到備用的節點上

l  實體bean本質上也是無狀態的。表面上看可以採用和無狀態會話bean一樣的方式集羣,但實際上很少廠商會對實體bean做集羣。因爲實體bean一般都是被其他會話bean調用的,因此通常都使用本地接口通訊,實在沒有集羣的必要

 

 

JMS和數據庫連接的集羣

目前一些數據庫產品已經可以集羣了,你可以部署成多份,每個節點之間可以同步。但是JDBC本質上是有狀態連接,和底層的socket緊密綁定。當某個JDBC連接突然中斷了,與之相關的對象也就費了,因此很難對JDBC集羣。Weblogic使用一種JDBC multipool,可以在JDBC斷開情況下,方便地進行重新連接

 

JMS的負載均衡和失效備援只在JMS broker上有實現,很少有廠商在JMS destination 的消息上實現了負載均衡

 

 

J2EE集羣的困惑

失效備援能夠防止所有錯誤嗎?——錯!

JBOSS的文檔花了整整一章的內容來提醒你:“你真的需要HTTP SESSION複製嗎”,有時候不用失效備援也能以經濟的方式獲得高可靠性。更何況,失效備援並沒有你想象中的那麼可靠

 

你也許認爲失效備援能夠在節點宕機時保護你的session數據,但你得清楚,這種保障是有條件的

 

回想一下作者在定義“失效備援”時,前提條件是“在兩個方法調用之間”!也就是說只有在第一個方法成功返回之後、第二個方法調用開始之前,失效備援才能起作用

 

假設某個方法處理到一半時服務器不幸掛掉了,客戶端一般只能收到錯誤消息。除非你這個方法恰好是“idempotent”的(即多次調用的結果都能保持一致,不會對環境造成任何改變,比如getter方法),那麼有些聰明的負載均衡器會嘗試找其他節點去調用這個方法

 

所以說“idempotent”這個概念非常重要,因爲客戶端壓根不知道是在什麼地方失敗的,而如果這個方法不是idempotent,那麼系統就可能處於一種不一致的狀態,很危險

 

你也許認爲事務性的方法就是idempotent的,畢竟事務可以回滾。但其實事務遠遠不能涵蓋整個遠程調用的範圍,比如服務器成功執行某事務性方法後,返回結果的過程中網絡崩潰了呢?

 

在比較嚴格的系統設計中,你根本不能令所有方法都idempotent,你能做的就是利用failover,儘可能減少錯誤而不是徹底杜絕錯誤。以某個網上商城爲例:每臺服務器都同時處理100個用戶請求,當某臺服務器崩潰時,如果沒有失效備援,那麼你會得罪一百個用戶;而如果有失效備援,可能只有不到20個用戶會發飆。你自己要權衡:

l  是得罪一百個客戶還是得罪20個客戶?

l  有沒有失效備援的服務器的價格差別

 

 

獨立的應用程序可以無縫地遷移到分佈式平臺上?——錯!

這只是某些廠商的廣告而已,不可輕信。如果是大型系統,那麼設計之初就應該全盤考慮集羣可能造成的影響

HTTP  SESSION

正如前文所述,HTTP SESSION的集羣會受到你使用的服務器的諸多限制。首先是可序列化的要求,在很多MVC架構中,session被用來存儲一些不可序列化的對象(比如servlet context);其次,序列化、特別是數據庫方式的序列化非常耗費資源,因此要集羣就儘量不要用session存儲大對象。如果是內存拷貝的方式,那麼就要考慮內存的限制和交叉引用的問題(交叉引用請參考前文);最後,你在集羣環境下改變session的屬性時,必須使用“setAttribute”方法,而在單機環境下卻沒這個限制。這麼做的主要原因是讓你的應用服務器能夠檢測到屬性改變,及時地備份已修改的屬性

 

緩存

大部分流行的應用服務器都會使用緩存來提升性能,但緩存一般都是爲單機環境設計的。集羣環境下如果使用緩存,那麼緩存之間的拷貝花費的性能將比緩存帶來的好處還多,適得其反

 

靜態變量

有一種很流行的J2EE設計模式“singleton(單體)”,是使用靜態變量的,這在單機環境下適用,但到了集羣就不行了,道理很簡單,每個JVM都有自己的靜態對象,“單體”也就失去意義了。比如要統計在線用戶數時,經常用一個靜態變量來存儲,但是在集羣環境下這種方法顯然失去作用。要使用靜態對象,最好把它放到一個數據庫中,才能實現全局的“單體”

 

外部資源

儘管J2EE規範並不推薦,但外部IO操作還是有用的,比如用來存放用戶上傳的文件。在集羣中,服務器是不能通過另一臺服務器把本地文件直接存放到別的機器上的,那麼還是要依靠數據庫來統一存放文件,或者你可以使用SAN這種集中式文件倉庫

 

專有服務

有些專有服務是只限於單機環境的,比如定時器服務(timer);再比如某些事件觸發類型的服務,如初始化服務,郵件提醒服務也屬於此列。這些服務一般針對一個特定條件只發生一次,拿去集羣沒什麼意義。JBOSS的“clustered singleton facility”就是用來保證所有服務器運行且只運行一次某種服務

 

 

分佈式系統比並列式系統更靈活?——未必

儘管EJB生來就是爲了分佈式、解耦合,但很多框架認爲把EJB層和web層放在一起也未嘗不是好事,或許更好

 

 

20:分佈式架構

 

如圖20,負載均衡器先將請求分發到適當服務器的web層,web層進一步判斷調用何處的EJB,這等於是做了兩次的負載均衡和失效備援。很多人認爲這種設計並不好:

l  首先,第二次的轉發根本沒有必要,每個服務器都有自己的webejb層,比起只調用內部的ejbweb層調用其他ejb層沒有任何的好處

l  第二次的失效備援也是沒有必要的,大部分廠商都把web容器和ejb容器實現爲在同一個jvm上跑,那樣一旦web容器掛了,ejb容器很難獨善其身

l  損失性能,這個不必解釋了,大量的服務器之間的調用對性能肯定有影響。

 

實際上,大部分廠商都讓web容器優先選擇同一個服務器上的ejb容器,這種方式稱作“並列式”,是分佈式的一種特例,如下圖

 

21:並列式

 

這樣引出一個有趣的問題:既然都放一塊了,爲什麼不直接用ejb的本地接口呢?雖然本地接口可以提高性能,但它卻把webejb緊耦合在一起了,負載均衡機制也就沒有辦法對其進行優化,特別是當你要變成分佈式的時候

此外很不幸的是,在集羣環境下本地接口的使用經常受到限制,因爲有本地接口的ejb通常是不可序列化的。所以有些應用服務器,比如sun JES,對本地接口的ejb做了特殊處理使其可以被序列化,從而保存到諸如session中去

 

還有一個問題是,既然大部分情況下並列式的性能都比較好,那還要分佈式幹什麼呢?其實在某些情況下還非得用分佈式不可:

l  除了web容器,富客戶端也要調用ejb組件

l  Web容器和ejb容器所處的安全級別不同,它們物流上也被放在不同的地方,中間加上一個防火牆

l  Ejbweb層的極度不對稱。指的是複雜度的不對稱,比如ejb層有大規模的運算,那就放在一臺高級的服務器上,而web容器只需放在一臺pc上即可

 

 

結論

集羣與單機環境是有很大不同的,各廠商的集羣實現也不同。最好在項目開始就考慮到集羣,使得你的系統更有擴展性,根據自身的需求選擇最合適的應用服務器,並且選購第三方軟件時也要考慮到對集羣的支持。最後,合適的架構可以讓你受益於集羣而不是讓集羣成爲你的噩夢

 

 

關於原作者

Wang Yu presently works for GPE group of Sun Microsystems as a Java technology engineer and technology architecture consultant. His duties include supporting local ISVs, evangelizing and consulting on important Java technologies such as J2EE, EJB, JSP/Servlet, JMS, Web services technologies. He can be reached at [email protected].

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章