Tomcat 的集群和負(fù)載均衡 - 第二部分在第一部分中,我簡述了具有可升級和高可靠性的大型J2EE系統(tǒng)在設(shè)計時需要考慮的各種因素。 討論Tomcat對集群、負(fù)載均衡、容錯和 session 復(fù)制等能力的支持。 在這個部分,我們將看到完整一個集群的架構(gòu)和部署集群過程的安裝和配置細(xì)節(jié)(通過運(yùn)行多個Tomcat服務(wù)器實(shí)例)。
+ 集群的設(shè)置
下面列出的是這個 Tomcat 集群例子要實(shí)現(xiàn)的目標(biāo):
* 可升級能力 * 容錯 * 動態(tài)配置,易于管理 * 自動發(fā)現(xiàn)新成員 * 失敗重啟和負(fù)載均衡,session數(shù)據(jù)內(nèi)存復(fù)制 * 可插拔/配置的負(fù)載均衡策略 * 當(dāng)一個成員加入或離開時,能通知組成員 * 通過多播的方式,無掉包的信息傳輸 * 集群對 web 應(yīng)用和服務(wù)器來說都是無縫的。
在這個集群環(huán)境中,安裝有四個 Tomcat 服務(wù)器實(shí)例。一個作負(fù)載均衡服務(wù)器,三個作集群。 集群以垂直縮放的方法設(shè)置(多個 Tomcat 服務(wù)器實(shí)例運(yùn)行在一臺機(jī)器上)。 下面是集群的主要組成部分的設(shè)置:
* 負(fù)載均衡 : 一個Tomcat實(shí)例,分發(fā)交易到集群的個節(jié)點(diǎn)上。代號TC-LB。 * 集群 : 集群包含3個Tomcat服務(wù)器實(shí)例,代號分別是 TC01, TC02 和 TC03。 * session 持久化 : 選擇內(nèi)存復(fù)制的方式。當(dāng)session對象改變時,session數(shù)據(jù)將被復(fù)制到所有3個集群成員。 * 失敗重啟 : Tomcat安裝時自帶的負(fù)載均衡器應(yīng)用不能處理失敗重啟。 我寫了一個工具類 ServerUtil ,在轉(zhuǎn)發(fā)請求給服務(wù)器之前檢查服務(wù)器狀態(tài)。 有種兩種方法檢查集群節(jié)點(diǎn)的狀態(tài)。在第一種方法中,使用 McastService 來檢測是否有一個指定的服務(wù)器實(shí)例運(yùn)行。 而第二種方法則通過以Web頁的URL為參數(shù)創(chuàng)建一個URL對象,驗(yàn)證集群節(jié)點(diǎn)的有效性。 要使用這個類,需要確保 catalina-cluster.jar(位于 %TOMCAT_HOME%/server/ 庫目錄) 和 commons-logging-api.jar(位于%TOMCAT_HOME%/bin 目錄) 文件在 classpath 中指定。
下面集群的主要組件的架構(gòu)圖。 圖1,Tomcat集群架構(gòu)圖
+ 安裝和配置 Tomcat實(shí)例
表1,本例中設(shè)置 Tomcat 集群環(huán)境所用到的硬件和軟件
Processor HP Pavilion Pentium III with 800 MHz Memory 512 MB RAM Hard Disk 40 GB Operating System Windows 2000 server with Service Pack 4 JDK Version 1.4.0_02 (Note: JDK version 1.4 or a later version is required to enable Tomcat Clustering) Tomcat Version 5.0.19 Tools Used Ant 1.6.1, Log4J, JMeter, JBuilder
+ 集群框架的主要元素
++ Java 類 * BaseLoadBalancingRule 抽象類,封裝通用的規(guī)則邏輯。在這個例子中的自定義負(fù)載均衡規(guī)則就是擴(kuò)展自這個基類。 * RandomRedirectRule 使用“隨機(jī)”的規(guī)則,定義重定向web請求到一個有效的服務(wù)器上的邏輯。使用當(dāng)前系統(tǒng)時間作為種子,生成一個隨機(jī)的號碼。 * RoundRobinRule 這個類定義一個負(fù)載均衡的邏輯,基于“輪循”規(guī)則。當(dāng)一個請求進(jìn)入,它將其重定向到集群成員列表中的下一個成員。 使用一個靜態(tài)變量來跟蹤下一個有效的集群成員,每處理一個請求,就將這個值加1。 * ServerUtil 一個工具類,用來檢測指定的集群節(jié)點(diǎn)是否有效。 這個類用 McastService (org.apache.catalina.cluster.mcast 包)來檢測某集群成員是否離開了這個組。
下面的類圖表示這些Java類之間的關(guān)系。 圖2 集群應(yīng)用類圖
++ 配置文件
* server.xml 用于對 Tomcat 服務(wù)器實(shí)例進(jìn)行集群配置。這個版本的Tomcat安裝后,server.xml文件中包含被注釋掉的集群配置細(xì)節(jié)。 * web.xml 在這個文件中可指明該web應(yīng)用的session數(shù)據(jù)需要被復(fù)制。 * rules.xml 這個文件用來定義的負(fù)載均衡規(guī)則。
++ 腳本 * test.jsp 一個簡單的測試 JSP 腳本,用于檢查服務(wù)器的狀態(tài)。顯示運(yùn)行的Tomcat實(shí)例的名字和系統(tǒng)時間。 * testLB.jsp 在本應(yīng)用中,這個是起始頁面。它使用 HTML 重定向?qū)?font face="Vera Sans YuanTi, serif">web請求轉(zhuǎn)發(fā)到負(fù)載均衡過濾器上。 * sessiondata.jsp 這個腳本用來驗(yàn)證當(dāng)一個集群節(jié)點(diǎn)掛起時,session數(shù)據(jù)并沒有丟失。顯示session的內(nèi)容,使用 HTML 字段操作 HTTP session 對象。 * build.xml Ant build 腳本,讓啟動和停止Tomcat實(shí)例的任務(wù)實(shí)現(xiàn)自動化(由Ant 1.6.1 用來執(zhí)行這個腳本)。一旦某個Tomcat實(shí)例啟動成功,你可以通過指定IP地址和端口號,調(diào)用test.jsp來驗(yàn)證該Tomcat實(shí)例是否在運(yùn)行。這個JSP頁將顯示當(dāng)前系統(tǒng)時間和Tomcat實(shí)例的名稱。你需要改變 build.properties 文件中的 home 目錄的指定,在你自己的環(huán)境中運(yùn)行這個腳本。
build 腳本中用于啟動或停止 Tomcat 實(shí)例的幾個 targets: * 調(diào)用 target “start.tomcat5x” 啟動一個特定的 Tomcat 實(shí)例(例如: tomcat50)。 * 調(diào)用 stop.tomcat5x 停止一個特定的Tomcat實(shí)例 * 調(diào)用 stop.alltomcats 中止所有運(yùn)行的 Tomcat 實(shí)例
+ 范例代碼
本例子的代碼 tomcatclustering.zip。安裝完 Tomcat 服務(wù)器實(shí)例后(4個),解壓這個zip文件中的文件到tomcat目錄。 例子代碼使用RoundRobinRule作為負(fù)載均衡規(guī)則。如果您想使用隨機(jī)的重定向規(guī)則,修改rules.xml文件(在tomcat50/webapps/balancer/WEB-INF/conf目錄中)。 注釋掉 關(guān)于 RoundRobinRule 的元素,取消關(guān)于 RandomRedirectRule 元素的注釋。 同樣,如果您想用兩個實(shí)例,而不是三個,注釋掉第三個,并改變maxServerInstances屬性的值為2(替換原來的3)。
注意:缺省情況下,tomcat安裝后會包含好幾個其他的應(yīng)用,我刪除了所有其他的web應(yīng)用(jsp-examples,等等),僅僅保留 balancer 和 本例的web應(yīng)用。
+ HTTP 請求流程
本例集群環(huán)境中的 web請求流程如下:
1. 運(yùn)行起始頁面(http://localhost:8080/balancer/testLB.jsp); 2. JSP將請求重定向到負(fù)載均衡過濾器(URL:http://localhost:8080/balancer/LoadBalancer) 3. 負(fù)載均衡器(TC-LB)攔截web請求,并根據(jù)配置文件中指定的負(fù)載均衡規(guī)則重定向到下一個有效的集群成員(TC01, TC02 或者 TC03); 4. 被選中的集群成員的sessiondata.jsp (位于 “clusterapp” web應(yīng)用)被調(diào)用; 5. 如果 session 被修改, ClusterAppSessionListener 的 session 監(jiān)聽器方法將被調(diào)用,用于記錄 session 修改事件; 6. sessiondata.jsp 在web瀏覽器上顯示session的詳細(xì)內(nèi)容(例如session id,最后訪問事件,等等); 7. 隨機(jī)停止一個或兩個集群節(jié)點(diǎn)(調(diào)用 Ant 腳本的 “stop.tomcat5x” target ); 8. 重復(fù)上面7個步驟,查看是否對某個有效的集群成員的請求失敗。同時,檢查session信息是否在集群成員內(nèi)部進(jìn)行無數(shù)據(jù)丟失的拷貝。
圖3 表示一個web請求的流程
集群應(yīng)用的序列圖
+ 集群的配置
在這個集群中,運(yùn)行一個“clusterapp”的web應(yīng)用。為優(yōu)化session復(fù)制,所有的實(shí)例擁有一樣的目錄結(jié)構(gòu)和內(nèi)容。
由于Tomcat服務(wù)器實(shí)例使用IP多播來傳輸session,我們必須確定集群機(jī)器上的IP多播功能是可用的。為驗(yàn)證,你可以運(yùn)行《如果編寫多播服務(wù)和客戶程序。Tomcat:The Definitive Guide》這本書中的例子Java程序MulticastNode,或者,參考http://java./docs/books/tutorial/networking/datagrams/broadcasting.html。
當(dāng)一個集群節(jié)點(diǎn)啟動,集群中的其他成員將在服務(wù)器控制臺上顯示一條記錄信息,說明一個成員已經(jīng)被添加到集群中。類似的,當(dāng)一個集群節(jié)點(diǎn)下線,其他的節(jié)點(diǎn)將在控制臺上顯示一個集群成員離開的記錄。 圖4 當(dāng)集群中添加或者刪除一個成員時所產(chǎn)生的記錄信息
按照下面的步驟可打開Tomcat服務(wù)器的集群和session復(fù)制功能:
1.所有的session屬性必須實(shí)現(xiàn)java.io.Serailizable接口 2.取消對server.xml文件中Cluster元素的注釋。userDirtyFlag和replicationMode兩個屬性用于優(yōu)化頻率和session復(fù)制機(jī)制。 3.取消對server.xml中Value元素的注釋。ReplicationValue用于攔截HTTP請求并在集群成員內(nèi)復(fù)制session數(shù)據(jù)。Value元素有一個“filter”的屬性,可以用來過濾不會對session進(jìn)行修改的請求(如HTML頁面和圖像文件)。 4.由于全部Tomcat實(shí)例都是運(yùn)行在同一臺機(jī)器上,每個Tomcat實(shí)例的tcpListenPort屬性需要設(shè)置成唯一。名字格式為 mcastXXX(mcastAddr, mcastPort, mcastFrequency, 和 mcastDropTime) 的屬性都是用于集群關(guān)系的多播ping,而名字格式為tcpXXX(tcpThreadCount, tcpListenAddress, tcpListenPort 和 tcpSelectorTimeout) 是用于 session 復(fù)制(下面的集群配置參數(shù)表顯示Tomcat服務(wù)器實(shí)例的不同配置) 5.web.xml meta文件(位于clusterapp\WEB-INF目錄)應(yīng)該擁有元素。為一個指定的web應(yīng)用復(fù)制session狀態(tài),distributable元素必須被定義。這表示如果你有不止一個web應(yīng)用需要session復(fù)制,那么你需要增加distributable到所有web應(yīng)用的web.xml文件中。《Tomcat:The Definitive Guide》這本書的“Tomcat集群”這章對這個問題有很好的解釋。
表2 集群的配置參數(shù)
注意:由于所有的集群成員都是運(yùn)行在同一臺機(jī)器上,他們使用同一個IP地址(127.0.0.1)。 如果你沒有使用Ant腳本啟動和停止Tomcat實(shí)例,不要在你的機(jī)器上設(shè)置CATALINA_HOME環(huán)境變量。如果這個變量被設(shè)置,所有的實(shí)例都嘗試使用同一個目錄(CATALINA_HOME 變量指定的)來啟動Tomcat實(shí)例。結(jié)果只有第一個實(shí)例能成功啟動,其他的實(shí)例會崩潰,出現(xiàn)邦定異常信息,通知端口已經(jīng)被使用:“java.net.BindException: Address already in use: JVM_Bind:8080”。
+ 負(fù)載均衡的設(shè)置 我寫了兩個簡單,自定義的負(fù)載均衡規(guī)則(RoundRobinRule 和 RandomRedirect),用于重定向進(jìn)入的web請求。這些規(guī)則都是基于負(fù)載均衡算法(例如輪循和隨機(jī)重定向)。你可以編寫基于其他因素(如加權(quán)和最后訪問時間等)類似的自定義負(fù)載均衡規(guī)則。Tomcat 負(fù)載均衡器提供一個樣例(基于參數(shù)的負(fù)載均衡規(guī)則),它根據(jù)HTTP請求的參數(shù)決定重定向web請求到不同的URL上。
保持 server.xml (TC-LB實(shí)例) 中關(guān)于集群和value元素的注釋狀態(tài),因?yàn)樵搶?shí)例并非集群成員。
+ 測試的設(shè)置
++ session持久化測試
在 session持久化測試中, 主要目標(biāo)是在一個web請求過程中驗(yàn)證當(dāng)一個集群成員崩潰后,session數(shù)據(jù)并沒有丟失。JSP sessiondata.jsp 用來顯示session內(nèi)容。這個腳本同時提供HTML text字段,用于添加/修改/刪除 session屬性。在添加屬性給HTTP session后,我隨機(jī)的停止集群節(jié)點(diǎn),并檢測有效的集群成員上的session。
++ 負(fù)載測試
負(fù)載測試的目的是研究自定義的負(fù)載均衡算法,當(dāng)一個或多個節(jié)點(diǎn)停止服務(wù)的情況下,web請求如何被有效的分發(fā)到指定的集群節(jié)點(diǎn)。JMeter負(fù)載測試工具就是用來模擬多并發(fā)web用戶的情況。
測試負(fù)載均衡的步驟如下:
1. 啟動負(fù)載均衡器和集群實(shí)例。 2. 運(yùn)行起始JSP 腳本(testLB.jsp)。 3. 通過手動停止一個或者多個容器來模擬服務(wù)器崩潰。 4. 檢查負(fù)載分發(fā)模式。 5. 重復(fù)100次步驟1至4。
所有的記錄信息被重定向到一個文本文件,叫tomcat_cluster.log(位于 tomcat50/webapps/balancer目錄)。在序列圖中(圖2)的所有web對象的響應(yīng)時間是使用Log4J信息記錄。表3是耗時(毫秒)表。
下表表示負(fù)載測試的耗時(使用RoundRobinRule算法)和負(fù)載分發(fā)百分比(使用RandomRedirectRule算法)。
Table 3. 負(fù)載測試的耗時
注意:所有的耗時是100個并發(fā)用戶的平均值。
表 4. 當(dāng)使用隨機(jī)負(fù)載均衡規(guī)則是的負(fù)載分發(fā)。
注意:負(fù)載分發(fā)的百分比也是基于100個并發(fā)用戶的負(fù)載。 + 總結(jié) 在session持久化測試中,增加session屬性后,其中的一個集群節(jié)點(diǎn)掛起,通過驗(yàn)證,證實(shí)在服務(wù)器停機(jī)時間,session屬性并沒有丟失。session屬性的具體內(nèi)容記錄在文本文件中。
在負(fù)載測試中,當(dāng)一個或者兩個服務(wù)器實(shí)例停止,僅有一個 Tomcat 實(shí)例運(yùn)行,回應(yīng)的時間比起所有三個實(shí)例都有效時長。當(dāng)原先停止的實(shí)例重新啟動,負(fù)載均衡器自動重新發(fā)現(xiàn)這些服務(wù)器有效,將接下來的請求重定到這些服務(wù)器實(shí)例上,馬上能提高回應(yīng)的時間。
這里用來發(fā)現(xiàn)集群成員是否有效的機(jī)制(ServerUtil)并非是最快的方法。
這個集群設(shè)置的一個缺陷是它僅僅提供一個負(fù)載均衡器。當(dāng)用作負(fù)載均衡器的 Tomcat 實(shí)例掛起時會發(fā)生什么事情呢?就沒有途徑轉(zhuǎn)發(fā)請求到集群,這個結(jié)果叫做單點(diǎn)失敗(SPoF).其中一個解決方法就是有另外一個Tomcat實(shí)例運(yùn)行著,作為一個備用負(fù)載均衡器。如果主負(fù)載均衡器崩潰時,備用均衡器將接替它的工作。典型的 高可靠性集群(HA) 包含兩個負(fù)載均衡器防止 SPoF 的情況發(fā)生。
在上面的例子中,所有Tomcat實(shí)例(包括負(fù)載均衡器)都是配置在同一臺機(jī)器上運(yùn)行。更好的設(shè)置就是在一臺獨(dú)立的機(jī)器上運(yùn)行負(fù)載均衡器。同樣,限制每臺機(jī)器擁有兩個集群節(jié)點(diǎn),充分利用水平縮放的方法來保證集群的效率。
對J2EE Web 應(yīng)用服務(wù)器來講,HTTP session 復(fù)制是一種昂貴的操作。J2EE集群環(huán)境下,session管理的實(shí)現(xiàn)應(yīng)該在項(xiàng)目的分析和設(shè)計階段中就需要考慮。編碼時必須想著集群環(huán)境。如果沒有在設(shè)計階段就考慮集群的實(shí)現(xiàn),為了讓應(yīng)用能在集群環(huán)境下工作,代碼可能需要全部重寫。這會造成非常大的影響。
如果web應(yīng)用支持各種對象緩存機(jī)制,那么在應(yīng)用開發(fā)的初始階段,集群環(huán)境中的緩存對象就應(yīng)該被考慮。這是非常重要的,因?yàn)閷τ谔峁┚_和即時的事務(wù)數(shù)據(jù)給Web用戶,在所有集群的節(jié)點(diǎn)中保持緩存數(shù)據(jù)的同步是非常危險的。
一旦J2EE集 群成功設(shè)置和運(yùn)行,它的管理和維護(hù)將變得非常重要。保持集群的運(yùn)行和將應(yīng)用的變化推到所有的集群節(jié)點(diǎn)上。需要有一個方法提供這些服務(wù),實(shí)現(xiàn)一個監(jiān)視器服 務(wù),周期性的檢測服務(wù)器的有效性,如果集群中有節(jié)點(diǎn)無效,它將會發(fā)出通知。這個服務(wù)有規(guī)律間隔的檢測失效的節(jié)點(diǎn),并從活動集群節(jié)點(diǎn)列表中刪除失效的節(jié)點(diǎn)。 它應(yīng)該擁有一種能力,當(dāng)改變和更新出現(xiàn)時,它能同步和更新集群中所有的服務(wù)器。由于對web應(yīng)用的所有的請求必須通過負(fù)載均衡系統(tǒng),這個系統(tǒng)能檢測到活動session的數(shù)量,活動session的數(shù)量,回應(yīng)次數(shù),高峰負(fù)載的次數(shù),高峰其間活動session的數(shù)量,低谷其間活動負(fù)載的數(shù)量,等等。這些審計信息可以為提高性能,優(yōu)化整個系統(tǒng)作為參考。
在這里,可以通過手動調(diào)整配置文件(server.xml 和 rules.xml)滿足設(shè)置集群和負(fù)載均衡器的所有配置需求。如果Jakarta項(xiàng)目組提供基于Web的集群管理工具,那我們就可以通過使用管理工具修改配置來管理集群和負(fù)載均衡。
+ 資源
* Tomcat: The Definitive Guide by Jason Brittain and Ian F. Darwin * Java Performance Tuning, 2nd Edition by Jack Shiraji * Creating Highly Available and Scalable Applications Using J2EE, The Middleware Company, EJB Essentials Training Class Material |
|