table

          J2EE集群原理 II

          J2EE集群原理 II

          二. JNDI集群
          Jndi集群對(duì)于EJB也是非常重要的,因?yàn)閹缀跛械腅JB都是從JNDI調(diào)用開始的
          I. 共享全局JNDI樹
          Weblogic和JBOSS都使用一個(gè)全局的、共享的、分布在整個(gè)集群系統(tǒng)的JNDI樹,對(duì)象被綁定到全局上下文,使用ip多播方式拷貝JNDI數(shù)據(jù)
          aaaaa

          圖十四:全局共享JNDI
          集群中的每個(gè)節(jié)點(diǎn)都有自己的命名服務(wù)器,并且自動(dòng)保存其他所有節(jié)點(diǎn)的JNDI數(shù)據(jù),因此這種結(jié)構(gòu)具有高度可靠性
          實(shí)際中,集群JNDI樹主要有兩個(gè)用途:一是用于部署,你只需要將某個(gè)EJB部署到一臺(tái)服務(wù)器上,系統(tǒng)會(huì)自動(dòng)將其拷貝到其他節(jié)點(diǎn)。二是在運(yùn)行中你可以用JNDI存取自己的對(duì)象,這些自定義對(duì)象同樣會(huì)被自動(dòng)拷貝到其他節(jié)點(diǎn)。
          II.獨(dú)立的JNDI樹
          Sun JES, IBM Websphere和其他廠商使用的是獨(dú)立的JNDI樹,各個(gè)節(jié)點(diǎn)擁有自己獨(dú)立的JNDI,而不會(huì)關(guān)心其他節(jié)點(diǎn)的JNDI。但這并不意味著它們不能實(shí)現(xiàn)集群,關(guān)鍵是每臺(tái)服務(wù)器上的配置要相同,應(yīng)用也要相同,這樣的話通過代理agent就能實(shí)現(xiàn)高性能的集群了

          Sun JES 和 IBM Websphere都在每個(gè)節(jié)點(diǎn)處安裝了一個(gè)agent,由console負(fù)責(zé)協(xié)調(diào)各個(gè)agent
          但這種方式不支持動(dòng)態(tài)綁定運(yùn)行時(shí)生成的對(duì)象,設(shè)計(jì)者的理由是:JNDI本身就是作為管理外部資源的中間層,運(yùn)行時(shí)對(duì)象綁定不在JNDI的職責(zé)范圍內(nèi),如果真的有這種需要,可以使用LDAP或者具有HA功能的數(shù)據(jù)庫(kù)。Sun和IBM都有自己的LDAP實(shí)現(xiàn)

          III. 中央型JNDI樹
          少數(shù)廠商采用中央型的JNDI,所有節(jié)點(diǎn)都去一個(gè)某個(gè)指定的JNDI服務(wù)器上獲取資源,當(dāng)然這對(duì)于客戶端來(lái)說是透明的。不過這種方式會(huì)大大增加安裝和管理的復(fù)雜性,因此被大部分廠商放棄

          怎樣開始連接JNDI呢
          使用JNDI,你必須知道提供JNDI服務(wù)的域名或IP以及端口,在全局和獨(dú)立型JNDI樹中,都存在著多個(gè)JNDI服務(wù)器,客戶端要連接哪一個(gè)呢,負(fù)載均衡和失敗恢復(fù)又是如何實(shí)現(xiàn)的呢?

          技術(shù)上來(lái)說,可以在客戶端和JNDI服務(wù)器之間放一個(gè)硬件或軟件實(shí)現(xiàn)的負(fù)載均衡器,來(lái)實(shí)現(xiàn)上述要求,不過大部分廠商都有更加簡(jiǎn)單的方法:

          * SUN JES 和JBOSS 能夠令“java.naming.provider.url”這一JNDI屬性支持用逗號(hào)分隔多個(gè)地址,例如,“java.naming.provider.url=server1:1100,server2:1100,server3:1100,server4:1100”,客戶端會(huì)逐個(gè)搜索,直到找到一個(gè)可用的為止

          * JBOSS還支持自動(dòng)找尋功能,即令“java.naming.provider.url”屬性為空,客戶端會(huì)自動(dòng)以網(wǎng)絡(luò)多播的方式尋找一個(gè)JNDI服務(wù)器作為查詢的起始點(diǎn)


          三. EJB集群原理
          EJB衍生自分布式計(jì)算技術(shù),服務(wù)器組件或富客戶端都能夠以標(biāo)準(zhǔn)協(xié)議(RMI/IIOP)調(diào)用遠(yuǎn)程的EJB,并且RMI/IIOP技術(shù)能夠屏蔽底層網(wǎng)絡(luò),使得EJB的調(diào)用對(duì)客戶透明化


          圖:EJB調(diào)用原理


          如圖,客戶端不是直接和EJB打交道,而是通過stub來(lái)代理。Stub負(fù)責(zé)利用RMI找到遠(yuǎn)程的EJB并進(jìn)行調(diào)用。EJB的調(diào)用過程分為下面三步(EJB2.0)

          1.從JNDI中查找EJBHOME stub
          2.利用home stub創(chuàng)建一個(gè)EJB Object stub
          3.利用EJB Object stub調(diào)用EJB的方法

          在JNDI查找時(shí),可以利用上文說到的方法進(jìn)行負(fù)載均衡;各廠商也會(huì)有自己專門的技術(shù)對(duì)stub的使用進(jìn)行負(fù)載均衡,一般有以下三種方式:

          Smart stub

          我們知道,stub可以通過JNDI來(lái)獲得和創(chuàng)建,甚至可以直接下載相應(yīng)的class文件來(lái)在運(yùn)行時(shí)動(dòng)態(tài)生成,而無(wú)須在客戶端本地的classpath中聲明


          圖十七:smart stub


          如圖十七,Weblogic 和JBOSS通過在stub的代碼中嵌入特殊的代碼來(lái)實(shí)現(xiàn)集群,這個(gè)stub的確相當(dāng)smart,它包含了所有能夠訪問的集群服務(wù)器節(jié)點(diǎn)、內(nèi)置了專門的集群算法來(lái)決定把請(qǐng)求發(fā)給何處,甚至當(dāng)集群的拓?fù)溆凶儠r(shí)(比如增加了節(jié)點(diǎn)),能動(dòng)態(tài)改變自身來(lái)適應(yīng)新的結(jié)構(gòu),無(wú)須手工干預(yù)
          Smart stub有以下幾個(gè)好處:

          1.節(jié)省大量服務(wù)器資源
          2.由于負(fù)載均衡是由客戶端處理,因此可以防止在服務(wù)器端放置負(fù)載均衡器而可能導(dǎo)致的單點(diǎn)失敗
          3.Stub可以動(dòng)態(tài)下載安裝,意味著無(wú)須手工維護(hù)

          IIOP Runtime Library

          Sun JES采用另一種方法,它直接修改客戶端的IIOP運(yùn)行時(shí)庫(kù)

          圖十八:IIOP Runtime

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

          Interceptor Proxy

          IBM Websphere使用Location Service Daemon (LSD)作為一個(gè)攔截器代理來(lái)實(shí)現(xiàn)EJB集群

          Figure 19: Interceptor Proxy

          使用這種機(jī)制,stub中包含至LSD的路由信息,而不是直接去找服務(wù)器節(jié)點(diǎn),這樣LSD就能獲得所有請(qǐng)求并進(jìn)行負(fù)載均衡了,不過這樣會(huì)大大增加管理和維護(hù)的成本

          EJB的集群支持
          調(diào)用EJB方法的過程中我們要和兩個(gè)stub打交道,一個(gè)是home stub,另一個(gè)是object stub,因此可以在兩個(gè)層面上實(shí)現(xiàn)負(fù)載均衡和失敗恢復(fù)

          1.EJBHOME STUB的集群實(shí)現(xiàn)
          由于EJBHOME STUB本身不包括任何客戶端信息,無(wú)論從哪個(gè)服務(wù)器上獲得的EJBHOME STUB都是一樣的,因此當(dāng)客戶端調(diào)用EJBHOME STUB的create等方法時(shí),就能利用一些負(fù)載均衡的算法選擇合適的服務(wù)器節(jié)點(diǎn)
          2.EJBOBJECT STUB的集群實(shí)現(xiàn)

          EJBOBJECT STUB包含業(yè)務(wù)接口,而且其本身也能夠含有集群節(jié)點(diǎn)的信息,但也不是所有的方法調(diào)用都能夠進(jìn)行負(fù)載均衡式的路由,得看EJB的類型是什么
          無(wú)狀態(tài)會(huì)話bean最容易實(shí)現(xiàn)負(fù)載均衡了,因?yàn)樗旧聿话囟ǖ目蛻粜畔?

          有狀態(tài)會(huì)話bean略有不同,因?yàn)樗旧戆蛻舳说臅?huì)話信息,因此有狀態(tài)bean的集群實(shí)現(xiàn)本質(zhì)上和HTTP session 無(wú)異,一般情況下客戶端的stub都是一直與某個(gè)節(jié)點(diǎn)上的EJB組件打交道的,除非中途出問題了才會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到備用的節(jié)點(diǎn)上

          實(shí)體bean本質(zhì)上也是無(wú)狀態(tài)的。表面上看可以采用和無(wú)狀態(tài)會(huì)話bean一樣的方式集群,但實(shí)際上很少?gòu)S商會(huì)對(duì)實(shí)體bean做集群。因?yàn)閷?shí)體bean一般都是被其他會(huì)話bean調(diào)用的,因此通常都使用本地接口通訊,實(shí)在沒有集群的必要

          四.JMS和數(shù)據(jù)庫(kù)連接的集群

          目前一些數(shù)據(jù)庫(kù)產(chǎn)品已經(jīng)可以集群了,你可以部署成多份,每個(gè)節(jié)點(diǎn)之間可以同步。但是JDBC本質(zhì)上是有狀態(tài)連接,和底層的socket緊密綁定。當(dāng)某個(gè)JDBC連接突然中斷了,與之相關(guān)的對(duì)象也就費(fèi)了,因此很難對(duì)JDBC集群。Weblogic使用一種JDBC multipool,可以在JDBC斷開情況下,方便地進(jìn)行重新連接

          JMS的負(fù)載均衡和失敗恢復(fù)只在JMS broker上有實(shí)現(xiàn),很少有廠商在JMS destination 的消息上實(shí)現(xiàn)了負(fù)載均衡

          五.關(guān)于J2EE集群的神話
          失敗恢復(fù)能夠防止所有錯(cuò)誤嗎?——錯(cuò)!
          JBOSS的文檔花了整整一章的內(nèi)容來(lái)提醒你:“你真的需要HTTP SESSION復(fù)制嗎”,有時(shí)候不用失敗恢復(fù)也能以經(jīng)濟(jì)的方式獲得高可靠性。更何況,失敗恢復(fù)并沒有你想象中的那么可靠

          你也許認(rèn)為失敗恢復(fù)能夠在節(jié)點(diǎn)宕機(jī)時(shí)保護(hù)你的session數(shù)據(jù),但你得清楚,這種保障是有代價(jià)的。

          回想一下作者在定義“失敗恢復(fù)”時(shí),前提條件是“在兩個(gè)方法調(diào)用之間”!也就是說只有在第一個(gè)方法成功返回之后、第二個(gè)方法調(diào)用開始之前,失敗恢復(fù)才能起作用

          假設(shè)某個(gè)方法處理到一半時(shí)服務(wù)器不幸掛掉了,客戶端一般只能收到錯(cuò)誤消息。除非你這個(gè)方法恰好是“idempotent”的(即多次調(diào)用的結(jié)果都能保持一致,不會(huì)對(duì)環(huán)境造成任何改變,比如getter方法),那么有些聰明的負(fù)載均衡器會(huì)嘗試找其他節(jié)點(diǎn)去調(diào)用這個(gè)方法

          所以說“idempotent”這個(gè)概念非常重要,因?yàn)榭蛻舳藟焊恢朗窃谑裁吹胤绞〉模绻@個(gè)方法不是idempotent,那么系統(tǒng)就可能處于一種不一致的狀態(tài),很危險(xiǎn)

          你也許認(rèn)為事務(wù)性的方法就是idempotent的,畢竟事務(wù)可以回滾。但其實(shí)事務(wù)遠(yuǎn)遠(yuǎn)不能涵蓋整個(gè)遠(yuǎn)程調(diào)用的范圍,比如服務(wù)器成功執(zhí)行某事務(wù)性方法后,返回結(jié)果的過程中網(wǎng)絡(luò)崩潰了呢?
          在比較嚴(yán)格的系統(tǒng)設(shè)計(jì)中,你根本不能令所有方法都idempotent,你能做的就是利用failover,盡可能減少錯(cuò)誤而不是徹底杜絕錯(cuò)誤。以某個(gè)網(wǎng)上商城為例:每臺(tái)服務(wù)器都同時(shí)處理100個(gè)用戶請(qǐng)求,當(dāng)某臺(tái)服務(wù)器崩潰時(shí),如果沒有失敗恢復(fù),那么你會(huì)得罪一百個(gè)用戶;而如果有失敗恢復(fù),可能只有不到20個(gè)用戶會(huì)發(fā)飆。你自己要權(quán)衡:
                  1.是得罪一百個(gè)客戶還是得罪20個(gè)客戶?
                  2.有沒有失敗恢復(fù)的服務(wù)器的價(jià)格差別

          獨(dú)立的應(yīng)用程序可以無(wú)縫地遷移到分布式平臺(tái)上?——錯(cuò)!
          這只是某些廠商的廣告而已,不可輕信。如果是大型系統(tǒng),那么設(shè)計(jì)之初就應(yīng)該全盤考慮集群可能造成的影響.

          HTTP  SESSION
          正如前文所述,HTTP SESSION的集群會(huì)受到你使用的服務(wù)器的諸多限制。首先是可序列化的要求,在很多MVC架構(gòu)中,session被用來(lái)存儲(chǔ)一些不可序列化的對(duì)象(比如servlet context);其次,序列化、特別是數(shù)據(jù)庫(kù)方式的序列化非常耗費(fèi)資源,因此要集群就盡量不要用session存儲(chǔ)大對(duì)象。如果是內(nèi)存拷貝的方式,那么就要考慮內(nèi)存的限制和交叉引用的問題(交叉引用請(qǐng)參考前文);最后,你在集群環(huán)境下改變session的屬性時(shí),必須使用“setAttribute”方法,而在單機(jī)環(huán)境下卻沒這個(gè)限制。這么做的主要原因是讓你的應(yīng)用服務(wù)器能夠檢測(cè)到屬性改變,及時(shí)地備份已修改的屬性

          緩存
          大部分流行的應(yīng)用服務(wù)器都會(huì)使用緩存來(lái)提升性能,但緩存一般都是為單機(jī)環(huán)境設(shè)計(jì)的。集群環(huán)境下如果使用緩存,那么緩存之間的拷貝花費(fèi)的性能將比緩存帶來(lái)的好處還多,適得其反

          靜態(tài)變量
          有一種很流行的J2EE設(shè)計(jì)模式“singleton(單體)”,是使用靜態(tài)變量的,這在單機(jī)環(huán)境下適用,但到了集群就不行了,道理很簡(jiǎn)單,每個(gè)JVM都有自己的靜態(tài)對(duì)象,“單體”也就失去意義了。比如要統(tǒng)計(jì)在線用戶數(shù)時(shí),經(jīng)常用一個(gè)靜態(tài)變量來(lái)存儲(chǔ),但是在集群環(huán)境下這種方法顯然失去作用。要使用靜態(tài)對(duì)象,最好把它放到一個(gè)數(shù)據(jù)庫(kù)中,才能實(shí)現(xiàn)全局的“單體”

          外部資源
          盡管J2EE規(guī)范并不推薦,但外部IO操作還是有用的,比如用來(lái)存放用戶上傳的文件。在集群中,服務(wù)器是不能通過另一臺(tái)服務(wù)器把本地文件直接存放到別的機(jī)器上的,那么還是要依靠數(shù)據(jù)庫(kù)來(lái)統(tǒng)一存放文件,或者你可以使用SAN這種集中式文件倉(cāng)庫(kù)

          專有服務(wù)
          有些專有服務(wù)是只限于單機(jī)環(huán)境的,比如定時(shí)器服務(wù)(timer);再比如某些事件觸發(fā)類型的服務(wù),如初始化服務(wù),郵件提醒服務(wù)也屬于此列。這些服務(wù)一般針對(duì)一個(gè)特定條件只發(fā)生一次,拿去集群沒什么意義。JBOSS的“clustered singleton facility”就是用來(lái)保證所有服務(wù)器運(yùn)行且只運(yùn)行一次某種服務(wù)

          分布式系統(tǒng)比并列式系統(tǒng)更靈活?——未必

          盡管EJB生來(lái)就是為了分布式、解耦合,但很多框架認(rèn)為把EJB層和web層放在一起也未嘗不是好事,或許更好

          圖20:分布式架構(gòu)

          如圖20,負(fù)載均衡器先將請(qǐng)求分發(fā)到適當(dāng)服務(wù)器的web層,web層進(jìn)一步判斷調(diào)用何處的EJB,這等于是做了兩次的負(fù)載均衡和失敗恢復(fù)。很多人認(rèn)為這種設(shè)計(jì)并不好:
                  1. 首先,第二次的轉(zhuǎn)發(fā)根本沒有必要,每個(gè)服務(wù)器都有自己的web和ejb層,比起只調(diào)用內(nèi)部的ejb,web層調(diào)用其他ejb層沒有任何的好處
                  2. 第二次的失敗恢復(fù)也是沒有必要的,大部分廠商都把web容器和ejb容器實(shí)現(xiàn)為在同一個(gè)jvm上跑,那樣一旦web容器掛了,ejb容器很難獨(dú)善其身
                  3. 損失性能,這個(gè)不必解釋了,大量的服務(wù)器之間的調(diào)用對(duì)性能肯定有影響。

          實(shí)際上,大部分廠商都讓web容器優(yōu)先選擇同一個(gè)服務(wù)器上的ejb容器,這種方式稱作“并列式”,是分布式的一種特例,如下圖

          圖21:并列式


          這樣引出一個(gè)有趣的問題:既然都放一塊了,為什么不直接用ejb的本地接口呢?雖然本地接口可以提高性能,但它卻把web和ejb緊耦合在一起了,負(fù)載均衡機(jī)制也就沒有辦法對(duì)其進(jìn)行優(yōu)化,特別是當(dāng)你要變成分布式的時(shí)候

          此外很不幸的是,在集群環(huán)境下本地接口的使用經(jīng)常受到限制,因?yàn)橛斜镜亟涌诘膃jb通常是不可序列化的。所以有些應(yīng)用服務(wù)器,比如sun JES,對(duì)本地接口的ejb做了特殊處理使其可以被序列化,從而保存到諸如session中去

          還有一個(gè)問題是,既然大部分情況下并列式的性能都比較好,那還要分布式干什么呢?其實(shí)在某些情況下還非得用分布式不可:
                  1. 除了web容器,富客戶端也要調(diào)用ejb組件
                  2. Web容器和ejb容器所處的安全級(jí)別不同,它們物流上也被放在不同的地方,中間加上一個(gè)防火墻
                  3.Ejb和web層的極度不對(duì)稱。指的是復(fù)雜度的不對(duì)稱,比如ejb層有大規(guī)模的運(yùn)算,那就放在一臺(tái)高級(jí)的服務(wù)器上,而web容器只需放在一臺(tái)pc上即可.

          六.結(jié)論
          集群與單機(jī)環(huán)境是有很大不同的,各廠商的集群實(shí)現(xiàn)也不同。最好在項(xiàng)目開始就考慮到集群,使得你的系統(tǒng)更有擴(kuò)展性,根據(jù)自身的需求選擇最合適的應(yīng)用服務(wù)器,并且選購(gòu)第三方軟件時(shí)也要考慮到對(duì)集群的支持。最后,合適的架構(gòu)可以讓你受益于集群而不是讓集群成為你的噩夢(mèng)


          關(guān)于原作者

          引用
          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 yu.wang@sun.com.

          posted on 2010-01-12 17:52 小卓 閱讀(387) 評(píng)論(0)  編輯  收藏 所屬分類: 服務(wù)器架構(gòu)


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 慈利县| 金山区| 桃江县| 祁连县| 阜城县| 射阳县| 江川县| 萝北县| 观塘区| 进贤县| 朝阳区| 太康县| 贵州省| 塔河县| 乐平市| 北安市| 建德市| 淄博市| 仙桃市| 孝感市| 会同县| 进贤县| 多伦县| 饶河县| 新竹县| 会东县| 天全县| 安岳县| 伊川县| 太原市| 双流县| 安远县| 寿阳县| 米林县| 郧西县| 安新县| 大化| 尤溪县| 甘孜县| 定西市| 永嘉县|