JBoss的集群策略分析(來源:http://www.yesky.com) 序言 在閱讀本文前,請確定您有以下基礎(chǔ),否則您可能會是在浪費您的時間: 1、 了解J2EE的一些基本概念 2、 了解集群的基本概念 3、 對JBOSS有一些大致的了解,可到http://www.上下載它。 JBOSS是一個開放源碼的、基于J2EE規(guī)范的應(yīng)用服務(wù)器,它實現(xiàn)了大多數(shù)的J2EE規(guī)范,除此之外,它還提供了一些J2EE中所沒有涉及到的企業(yè)級功能,例如集群。本文主要描述JBOSS采取的集群策略,并重點介紹它的負載平衡與失效轉(zhuǎn)發(fā)機制。 由于JBOSS是一個建立在J2EE規(guī)范上的應(yīng)用服務(wù)器,因此在開始之前,我們還是簡單地介紹一下J2EE規(guī)范:J2EE是一套針對于企業(yè)級分布式應(yīng)用的計算環(huán)境,它定義了動態(tài)WEB頁面功能(servlet和jsp),商業(yè)組件(EJB),異步消息傳輸機制(JMS),名稱和目錄定位服務(wù)(JNDI),數(shù)據(jù)庫訪問(JDBC),與子系統(tǒng)的連接器(JCA),安全服務(wù)等等。 但美中不足的是J2EE并沒有定義一些企業(yè)級應(yīng)用所必須的規(guī)范,例如集群,所以集群的實現(xiàn)只能由各廠商自行來設(shè)計實現(xiàn)。要實現(xiàn)基于J2EE規(guī)范的集群,我們通常要做如下考慮:集群的管理、負載平衡、失效轉(zhuǎn)發(fā)、服務(wù)端狀態(tài)的復(fù)制(例如JSP中的session),還要考慮同步和異步的問題(例如JMS服務(wù)就是異步方式)。如果要對這些內(nèi)容做一個全面的闡述的話,估計可以寫成一本書了:) 因此本文主要探討的是:怎樣實現(xiàn)無狀態(tài)EJB的負載平衡與失效轉(zhuǎn)發(fā)機制? 1999年,Marc Fleury建立了JBOSS開源項目,現(xiàn)在它有差不多100個活躍的開發(fā)者,30個核心開發(fā)者,每月高達35萬次的下載量,它當前的最高穩(wěn)定版是3.2版,4.0版正在穩(wěn)定之中,自從JBOSS3.0開始就加入了集群技術(shù),幾乎能對任何J2EE規(guī)范進行集群管理,如JNDI、JSP中的session、EJB等等。更令人振奮的是,即將發(fā)行的JBOSS4.0將會對JMS也加入集群管理特色。
EJB集群在JBOSS中的實現(xiàn) 下面言歸正傳,上圖大致描述了一個客戶端調(diào)用JBOSS中的EJB的過程。在JBOSS中,客戶端并不直接調(diào)用EJB對像,而采用了一個迂回的方法,更專業(yè)的說是一種設(shè)計模式――代理模式,真正與客戶端交互的是一個代理對像①,這個代理對像一般由客戶端通過JNDI技術(shù)來取得的。而具體的代理對像的實現(xiàn)就由各廠商自完成了,在JBOSS中,一個代理對像是一段精心設(shè)計的復(fù)雜代碼。 但在客戶端看來,調(diào)用一個代理對像好像就是在調(diào)用那個實際的EJB對像,雖然事實并非如此。在這里JBOSS耍了一個小把戲,代理對像雖然實現(xiàn)了與EJB對像相同的接口,但它實際上是把客戶端對它的調(diào)用轉(zhuǎn)發(fā)到了它在服務(wù)端的另一個伙伴身上②,同時,這個伙伴同樣定義了客戶端所要求的一些EJB接口,當這些接口被調(diào)用時③,精彩的部分開始了,JBOSS把客戶端發(fā)過來的各種各樣不同的調(diào)用全部轉(zhuǎn)換成為一個統(tǒng)一格式的接口④(在本文中我們暫且稱客戶端發(fā)出的調(diào)用為應(yīng)用級接口,而JBOSS生成的統(tǒng)一格式的接口稱為系統(tǒng)級接口)。當轉(zhuǎn)換完成后,所有的應(yīng)用級接口變成了系統(tǒng)級接口⑤。為了能更清楚地闡述這個問題,我們假設(shè)客戶端向EJB對像發(fā)出如下調(diào)用:
這個調(diào)用實際上被JBOSS轉(zhuǎn)換成了如下的系統(tǒng)級調(diào)用:
但這個invocation到底是什么呢?實際上它是類Invocation的一個實例,這里有它的一個簡單的說明:
當應(yīng)用級接口被轉(zhuǎn)換成為了系統(tǒng)級接口之后,它將經(jīng)過一系列的攔截器(⑥至⑦)。在這里我首先要說明一下什么是攔截器,實際上,它是JBOSS中獨具特色的一個設(shè)計思路,一個攔截器就好像是一張過濾網(wǎng),它用來對客戶端的調(diào)用進行攔截,并對其進行一些處理,比如檢查客戶端調(diào)用的合法性、實現(xiàn)安全策略、對事務(wù)進行支持等。值得一提的是,JBOSS的集群管理也是通過攔截器來實現(xiàn)的,更令人欣慰的是,JBOSS的設(shè)計者并沒有將這個攔截器固化在其核心內(nèi),而是采用一種插件式(plug-in)的方法來設(shè)計,因此你只要實現(xiàn)它的插件接口,你甚至可以寫出自己的攔截器來,當然,這已不屬于本文的討論范圍之內(nèi)了。 值得注意的是最后一個攔截器,它有一些特殊,因為它才真正地執(zhí)行對實際的EJB的調(diào)用⑧,它能檢測到客戶端是否和EJB對像在同一個Java虛擬機中,如果是的話,它只是簡單地將這個調(diào)用直接傳給EJB對像,這樣做的原因是可以避免由于網(wǎng)絡(luò)傳輸帶來的不必要的開銷,使用調(diào)用速度大大加快。 上圖中的3種方案都有其利弊,但我們覺得最后一個方法要比前2個好,原因如下: 因此,我們選擇了最后一種方案來做為JBOSS的集群策略。其實,只要大家再仔細回顧一下前面的部分,就會發(fā)現(xiàn)我們先前描述的方案不正是第3種方案嗎?但我們現(xiàn)在必須對這個策略在以下幾個方面做一些更深入的分析: 負載平衡的設(shè)計策略 前面已經(jīng)說過,JBOSS的負載平衡與失效轉(zhuǎn)發(fā)策略是由最后一個攔截器實現(xiàn)的(上圖中的①),然而我們要考慮的是雖然客戶端只發(fā)出一個調(diào)用,但針對于代理對像的調(diào)用可能包含多個可用的服務(wù)器結(jié)點,其個數(shù)等于集群中所有有效節(jié)點之和(參見上圖中的②),那么到底是由誰來決定這個策略的呢?這個工作由一個叫插件式的負載平衡策略來實施的(在下一段中簡稱策略①,如下圖)。 當客戶端調(diào)用到達最后一個攔截器的時候,攔截器會請求策略①來為它選擇一個服務(wù)器結(jié)點。如果此結(jié)點有效且調(diào)用成功,則結(jié)果會返回給代理對像,如果失敗了,攔截器不會直接將錯誤返回給代理對像,而是將這個錯誤信息報告給策略①,并請求它再為客戶端選擇一個新節(jié)點。 但還有一個問題值得考慮的,就是對一些致命性錯誤的處理。例如某個數(shù)據(jù)庫服務(wù)器突然崩潰了,那么最后一個攔截器將無法對此進行失效轉(zhuǎn)發(fā)了,因為不管選擇哪個服務(wù)器結(jié)點都不能解決這個問題了,在這里攔截器會將錯誤報告給客戶端,并由其自已做出決定。 IT界里好像有這樣一個原理,就是"越是可擴展性強,靈活的東西實施起來就越復(fù)雜"。在JBOSS中也不例外,但幸運的是這些工作并沒為給客戶端帶來額外的編程負擔(dān),因為所有策略的配置都是在服務(wù)器完成的。 JBOSS的集群配置遵循XML規(guī)范,下面是的一個普通EJB對像的典型集群配置:
上述配置說明了一個名為MySessionBean的會話Bean的集群策略,它定義了名為DefaultPartion的缺省策略名稱,并定義了2個具體的策略。當然,如果你覺得它比較復(fù)雜,而只想用JBOSS缺省的集群策略的話,可以將整個<cluster-config>標簽去掉。 服務(wù)器結(jié)點拓撲圖的刷新 JBOSS的集群實現(xiàn)是動態(tài)的,也就是說你可以動態(tài)地往集群中加入一個新節(jié)點或關(guān)閉任意一個節(jié)點,而不用費力地維護一張靜態(tài)的拓撲圖,就好像是JBOSS自己有能力管理集群一樣。這個思想夠先進吧?但與此同時它也帶來了一些令人頭痛的問題,請先看下圖: 由于JBOSS的集群策略是在客戶端進行的,那么客戶端在調(diào)用EJB的時候會將所有必須的組件下載下來,然后由其進行集群決策。如果我們設(shè)T為時間,且t0<t1<t2,那么當處于t0時刻時,集群拓撲圖中包含server1和server2兩個節(jié)點,客戶端的調(diào)用被轉(zhuǎn)發(fā)到了結(jié)點2上。當處于t1時刻時,server1和server2全部都崩潰了。當處于t2時刻時,管理員增加了server3和server4兩個節(jié)點,但客戶端的拓撲圖中還只是包含原先的server1和server2兩節(jié)點的信息,因為它無法知道這新加入的2個節(jié)點。 為了解決這個問題,JBOSS是這樣設(shè)計的,在客戶端的每次對某個節(jié)點調(diào)用后,服務(wù)器節(jié)點自動檢查客戶的拓撲圖是不是最新的,如果不是,則向客戶端發(fā)送新的拓撲圖,如下圖所示: 當客戶端進行調(diào)用時,代理對像對其進行了一個小小的包裝,它將系統(tǒng)級調(diào)用invocation和自已現(xiàn)在的拓撲圖(JBOSS開發(fā)者稱它為view ID)發(fā)送到服務(wù)端,而服務(wù)端則檢查它自己的view ID是否與代理對像中的view ID吻合。這里我們先簡單介紹一下view ID,它實際上就是包含所有服務(wù)器節(jié)點的一個哈希表,至于為什么要用哈希表是因為它生成方便(java編譯器自帶)、存取快速,無須考慮排序問題。 下面接著講述,如果代理對像的view ID與服務(wù)端節(jié)點的view ID相吻合的話,服務(wù)端將直接把結(jié)果傳給EJB對像,并將結(jié)果返回。 如果服務(wù)器集群拓撲產(chǎn)生了變化,則會導(dǎo)致它們不吻合。這時服務(wù)器節(jié)點同樣也將調(diào)用EJB對像,但此時返回的結(jié)果有所不同,它除了返回客戶端的結(jié)果外,還要為代理對像返回一個最新的view ID,并通知代理對像:"喂,你的拓撲圖太舊了,我發(fā)了份新的,你趕快更新一下吧!" 當代理對像收到這個消息后會更新自己的view ID,并將結(jié)果返回客戶端代碼。
性能考慮 結(jié)論 |
|
來自: david.tao > 《服務(wù)器集群》