英文原版,中文版由
鐘子昌翻譯整理
在第一部分中,我簡(jiǎn)述了具有可升級和高可靠性的大型J2EE系統在設計時(shí)需要考慮的各種因素。
討論Tomcat對集群、負載均衡、容錯和 session 復制等能力的支持。
在這個(gè)部分,我們將看到完整一個(gè)集群的架構和部署集群過(guò)程的安裝和配置細節(通過(guò)運行多個(gè)Tomcat服務(wù)器實(shí)例)。
+ 集群的設置
下面列出的是這個(gè) Tomcat 集群例子要實(shí)現的目標:
* 可升級能力
* 容錯
* 動(dòng)態(tài)配置,易于管理
* 自動(dòng)發(fā)現新成員
* 失敗重啟和負載均衡,session數據內存復制
* 可插拔/配置的負載均衡策略
* 當一個(gè)成員加入或離開(kāi)時(shí),能通知組成員
* 通過(guò)多播的方式,無(wú)掉包的信息傳輸
* 集群對 web 應用和服務(wù)器來(lái)說(shuō)都是無(wú)縫的。
在這個(gè)集群環(huán)境中,安裝有四個(gè) Tomcat 服務(wù)器實(shí)例。一個(gè)作負載均衡服務(wù)器,三個(gè)作集群。
集群以垂直縮放的方法設置(多個(gè) Tomcat 服務(wù)器實(shí)例運行在一臺機器上)。
下面是集群的主要組成部分的設置:
* 負載均衡 : 一個(gè)Tomcat實(shí)例,分發(fā)交易到集群的個(gè)節點(diǎn)上。代號TC-LB。
* 集群 : 集群包含3個(gè)Tomcat服務(wù)器實(shí)例,代號分別是 TC01, TC02 和 TC03。
* session 持久化 : 選擇內存復制的方式。當session對象改變時(shí),session數據將被復制到所有3個(gè)集群成員。
* 失敗重啟 : Tomcat安裝時(shí)自帶的負載均衡器應用不能處理失敗重啟。
我寫(xiě)了一個(gè)工具類(lèi) ServerUtil ,在轉發(fā)請求給服務(wù)器之前檢查服務(wù)器狀態(tài)。
有種兩種方法檢查集群節點(diǎn)的狀態(tài)。在第一種方法中,使用 McastService 來(lái)檢測是否有一個(gè)指定的服務(wù)器實(shí)例運行。
而第二種方法則通過(guò)以Web頁(yè)的URL為參數創(chuàng )建一個(gè)URL對象,驗證集群節點(diǎn)的有效性。
要使用這個(gè)類(lèi),需要確保 catalina-cluster.jar(位于 %TOMCAT_HOME%/server/ 庫目錄)
和 commons-logging-api.jar(位于%TOMCAT_HOME%/bin 目錄) 文件在 classpath 中指定。
下面集群的主要組件的架構圖。
圖1,Tomcat集群架構圖
+ 安裝和配置 Tomcat實(shí)例
表1,本例中設置 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 類(lèi)
* BaseLoadBalancingRule
抽象類(lèi),封裝通用的規則邏輯。在這個(gè)例子中的自定義負載均衡規則就是擴展自這個(gè)基類(lèi)。
* RandomRedirectRule
使用“隨機”的規則,定義重定向web請求到一個(gè)有效的服務(wù)器上的邏輯。使用當前系統時(shí)間作為種子,生成一個(gè)隨機的號碼。
* RoundRobinRule
這個(gè)類(lèi)定義一個(gè)負載均衡的邏輯,基于“輪循”規則。當一個(gè)請求進(jìn)入,它將其重定向到集群成員列表中的下一個(gè)成員。
使用一個(gè)靜態(tài)變量來(lái)跟蹤下一個(gè)有效的集群成員,每處理一個(gè)請求,就將這個(gè)值加1。
* ServerUtil
一個(gè)工具類(lèi),用來(lái)檢測指定的集群節點(diǎn)是否有效。
這個(gè)類(lèi)用 McastService (org.apache.catalina.cluster.mcast 包)來(lái)檢測某集群成員是否離開(kāi)了這個(gè)組。
下面的類(lèi)圖表示這些Java類(lèi)之間的關(guān)系。
圖2 集群應用類(lèi)圖
++ 配置文件
* server.xml
用于對 Tomcat 服務(wù)器實(shí)例進(jìn)行集群配置。這個(gè)版本的Tomcat安裝后,server.xml文件中包含被注釋掉的集群配置細節。
* web.xml
在這個(gè)文件中可指明該web應用的session數據需要被復制。
* rules.xml
這個(gè)文件用來(lái)定義的負載均衡規則。
++ 腳本
* test.jsp
一個(gè)簡(jiǎn)單的測試 JSP 腳本,用于檢查服務(wù)器的狀態(tài)。顯示運行的Tomcat實(shí)例的名字和系統時(shí)間。
* testLB.jsp
在本應用中,這個(gè)是起始頁(yè)面。它使用 HTML 重定向將web請求轉發(fā)到負載均衡過(guò)濾器上。
* sessiondata.jsp
這個(gè)腳本用來(lái)驗證當一個(gè)集群節點(diǎn)掛起時(shí),session數據并沒(méi)有丟失。顯示session的內容,使用 HTML 字段操作 HTTP session 對象。
* build.xml
Ant build 腳本,讓啟動(dòng)和停止Tomcat實(shí)例的任務(wù)實(shí)現自動(dòng)化(由Ant 1.6.1 用來(lái)執行這個(gè)腳本)。一旦某個(gè)Tomcat實(shí)例啟動(dòng)成功,你可以通過(guò)指定IP地址和端口號,調用test.jsp來(lái)驗證該Tomcat實(shí)例是否在運行。這個(gè)JSP頁(yè)將顯示當前系統時(shí)間和Tomcat實(shí)例的名稱(chēng)。你需要改變 build.properties 文件中的 home 目錄的指定,在你自己的環(huán)境中運行這個(gè)腳本。
build 腳本中用于啟動(dòng)或停止 Tomcat 實(shí)例的幾個(gè) targets:
* 調用 target “start.tomcat5x” 啟動(dòng)一個(gè)特定的 Tomcat 實(shí)例(例如: tomcat50)。
* 調用 stop.tomcat5x 停止一個(gè)特定的Tomcat實(shí)例
* 調用 stop.alltomcats 中止所有運行的 Tomcat 實(shí)例
+ 范例代碼
本例子的代碼
tomcatclustering.zip。安裝完 Tomcat 服務(wù)器實(shí)例后(4個(gè)),解壓這個(gè)zip文件中的文件到tomcat目錄。
例子代碼使用RoundRobinRule作為負載均衡規則。如果您想使用隨機的重定向規則,修改rules.xml文件(在tomcat50/webapps/balancer/WEB-INF/conf目錄中)。
注釋掉 關(guān)于 RoundRobinRule 的元素,取消關(guān)于 RandomRedirectRule 元素的注釋。 同樣,如果您想用兩個(gè)實(shí)例,而不是三個(gè),注釋掉第三個(gè),并改變maxServerInstances屬性的值為2(替換原來(lái)的3)。
注意:缺省情況下,tomcat安裝后會(huì )包含好幾個(gè)其他的應用,我刪除了所有其他的web應用(jsp-examples,等等),僅僅保留 balancer 和 本例的web應用。
+ HTTP 請求流程
本例集群環(huán)境中的 web請求流程如下:
1. 運行起始頁(yè)面(http://localhost:8080/balancer/testLB.jsp);
2. JSP將請求重定向到負載均衡過(guò)濾器(URL:http://localhost:8080/balancer/LoadBalancer)
3. 負載均衡器(TC-LB)攔截web請求,并根據配置文件中指定的負載均衡規則重定向到下一個(gè)有效的集群成員(TC01, TC02 或者 TC03);
4. 被選中的集群成員的sessiondata.jsp (位于 “clusterapp” web應用)被調用;
5. 如果 session 被修改, ClusterAppSessionListener 的 session 監聽(tīng)器方法將被調用,用于記錄 session 修改事件;
6. sessiondata.jsp 在web瀏覽器上顯示session的詳細內容(例如session id,最后訪(fǎng)問(wèn)事件,等等);
7. 隨機停止一個(gè)或兩個(gè)集群節點(diǎn)(調用 Ant 腳本的 “stop.tomcat5x” target );
8. 重復上面7個(gè)步驟,查看是否對某個(gè)有效的集群成員的請求失敗。同時(shí),檢查session信息是否在集群成員內部進(jìn)行無(wú)數據丟失的拷貝。
圖3 表示一個(gè)web請求的流程
集群應用的序列圖
+ 集群的配置
在這個(gè)集群中,運行一個(gè)“clusterapp”的web應用。為優(yōu)化session復制,所有的實(shí)例擁有一樣的目錄結構和內容。
由于Tomcat服務(wù)器實(shí)例使用IP多播來(lái)傳輸session,我們必須確定集群機器上的IP多播功能是可用的。為驗證,你可以運行《如果編寫(xiě)多播服務(wù)和客戶(hù)程序。Tomcat:The Definitive Guide》這本書(shū)中的例子Java程序MulticastNode,或者,參考http://java.sun.com/docs/books/tutorial/networking/datagrams/broadcasting.html。
當一個(gè)集群節點(diǎn)啟動(dòng),集群中的其他成員將在服務(wù)器控制臺上顯示一條記錄信息,說(shuō)明一個(gè)成員已經(jīng)被添加到集群中。類(lèi)似的,當一個(gè)集群節點(diǎn)下線(xiàn),其他的節點(diǎn)將在控制臺上顯示一個(gè)集群成員離開(kāi)的記錄。
圖4 當集群中添加或者刪除一個(gè)成員時(shí)所產(chǎn)生的記錄信息
按照下面的步驟可打開(kāi)Tomcat服務(wù)器的集群和session復制功能:
1.所有的session屬性必須實(shí)現java.io.Serailizable接口
2.取消對server.xml文件中Cluster元素的注釋。userDirtyFlag和replicationMode兩個(gè)屬性用于優(yōu)化頻率和session復制機制。
3.取消對server.xml中Value元素的注釋。ReplicationValue用于攔截HTTP請求并在集群成員內復制session數據。Value元素有一個(gè)“filter”的屬性,可以用來(lái)過(guò)濾不會(huì )對session進(jìn)行修改的請求(如HTML頁(yè)面和圖像文件)。
4.由于全部Tomcat實(shí)例都是運行在同一臺機器上,每個(gè)Tomcat實(shí)例的tcpListenPort屬性需要設置成唯一。名字格式為 mcastXXX(mcastAddr, mcastPort, mcastFrequency, 和 mcastDropTime) 的屬性都是用于集群關(guān)系的多播ping,而名字格式為tcpXXX(tcpThreadCount, tcpListenAddress, tcpListenPort 和 tcpSelectorTimeout) 是用于 session 復制(下面的集群配置參數表顯示Tomcat服務(wù)器實(shí)例的不同配置)
5.web.xml meta文件(位于clusterapp\WEB-INF目錄)應該擁有元素。為一個(gè)指定的web應用復制session狀態(tài),distributable元素必須被定義。這表示如果你有不止一個(gè)web應用需要session復制,那么你需要增加distributable到所有web應用的web.xml文件中?!?a target="_blank" >Tomcat:The Definitive Guide》這本書(shū)的“Tomcat集群”這章對這個(gè)問(wèn)題有很好的解釋。
表2 集群的配置參數
配置參數 實(shí)例 1 實(shí)例 2 實(shí)例 3 實(shí)例 4
Instance Type 負載均衡器 集群節點(diǎn)1 集群節點(diǎn)2 集群節點(diǎn)3
Code name TC-LB TC01 TC02 TC03
Home Directory c:/web/tomcat50 c:/web/tomcat51 c:/web/tomcat52 c:/web/tomcat53
Server Port 8005 9005 10005 11005
Connector 8080 9080 10080 11080
Coyote/JK2 AJP Connector 8009 9009 10009 11009
Cluster mcastAddr 228.0.0.4 228.0.0.4 228.0.0.4 228.0.0.4
Cluster mcastPort 45564 45564 45564 45564
tcpListenAddress 127.0.0.1 127.0.0.1 127.0.0.1 127.0.0.1
Cluster tcpListenPort 4000 4001 4002 4003
注意:由于所有的集群成員都是運行在同一臺機器上,他們使用同一個(gè)IP地址(127.0.0.1)。
如果你沒(méi)有使用Ant腳本啟動(dòng)和停止Tomcat實(shí)例,不要在你的機器上設置CATALINA_HOME環(huán)境變量。如果這個(gè)變量被設置,所有的實(shí)例都嘗試使用同一個(gè)目錄(CATALINA_HOME 變量指定的)來(lái)啟動(dòng)Tomcat實(shí)例。結果只有第一個(gè)實(shí)例能成功啟動(dòng),其他的實(shí)例會(huì )崩潰,出現邦定異常信息,通知端口已經(jīng)被使用:“java.net.BindException: Address already in use: JVM_Bind:8080”。
+ 負載均衡的設置
我寫(xiě)了兩個(gè)簡(jiǎn)單,自定義的負載均衡規則(RoundRobinRule 和 RandomRedirect),用于重定向進(jìn)入的web請求。這些規則都是基于負載均衡算法(例如輪循和隨機重定向)。你可以編寫(xiě)基于其他因素(如加權和最后訪(fǎng)問(wèn)時(shí)間等)類(lèi)似的自定義負載均衡規則。Tomcat 負載均衡器提供一個(gè)樣例(基于參數的負載均衡規則),它根據HTTP請求的參數決定重定向web請求到不同的URL上。
保持 server.xml (TC-LB實(shí)例) 中關(guān)于集群和value元素的注釋狀態(tài),因為該實(shí)例并非集群成員。
+ 測試的設置
++ session持久化測試
在 session持久化測試中, 主要目標是在一個(gè)web請求過(guò)程中驗證當一個(gè)集群成員崩潰后,session數據并沒(méi)有丟失。JSP sessiondata.jsp 用來(lái)顯示session內容。這個(gè)腳本同時(shí)提供HTML text字段,用于添加/修改/刪除 session屬性。在添加屬性給HTTP session后,我隨機的停止集群節點(diǎn),并檢測有效的集群成員上的session。
++ 負載測試
負載測試的目的是研究自定義的負載均衡算法,當一個(gè)或多個(gè)節點(diǎn)停止服務(wù)的情況下,web請求如何被有效的分發(fā)到指定的集群節點(diǎn)。JMeter負載測試工具就是用來(lái)模擬多并發(fā)web用戶(hù)的情況。
測試負載均衡的步驟如下:
1. 啟動(dòng)負載均衡器和集群實(shí)例。
2. 運行起始JSP 腳本(testLB.jsp)。
3. 通過(guò)手動(dòng)停止一個(gè)或者多個(gè)容器來(lái)模擬服務(wù)器崩潰。
4. 檢查負載分發(fā)模式。
5. 重復100次步驟1至4。
所有的記錄信息被重定向到一個(gè)文本文件,叫tomcat_cluster.log(位于 tomcat50/webapps/balancer目錄)。在序列圖中(圖2)的所有web對象的響應時(shí)間是使用Log4J信息記錄。表3是耗時(shí)(毫秒)表。
下表表示負載測試的耗時(shí)(使用RoundRobinRule算法)和負載分發(fā)百分比(使用RandomRedirectRule算法)。
Table 3. 負載測試的耗時(shí)
# Scenario testLB.jsp
(ms) RoundRobinRule
(ms) sessiondata.jsp
(ms) Total
(ms)
1 三個(gè)服務(wù)器都在運行 54 76 12 142
2 兩個(gè)服務(wù)器實(shí)例在運行(TC02 was stopped) 55 531 14 600
3 一個(gè)服務(wù)器在運行
(TC01 and TC02 were stopped) 56 1900 11 1967
注意:所有的耗時(shí)是100個(gè)并發(fā)用戶(hù)的平均值。
表 4. 當使用隨機負載均衡規則是的負載分發(fā)。
# Scenario TC01 (%) TC02 (%) TC03 (%)
1 所有服務(wù)實(shí)例在運行 30 46 24
2 兩個(gè)服務(wù)實(shí)例在運行 (TC02 was stopped) 56 0 44
注意:負載分發(fā)的百分比也是基于100個(gè)并發(fā)用戶(hù)的負載。
+ 總結
在session持久化測試中,增加session屬性后,其中的一個(gè)集群節點(diǎn)掛起,通過(guò)驗證,證實(shí)在服務(wù)器停機時(shí)間,session屬性并沒(méi)有丟失。session屬性的具體內容記錄在文本文件中。
在負載測試中,當一個(gè)或者兩個(gè)服務(wù)器實(shí)例停止,僅有一個(gè) Tomcat 實(shí)例運行,回應的時(shí)間比起所有三個(gè)實(shí)例都有效時(shí)長(cháng)。當原先停止的實(shí)例重新啟動(dòng),負載均衡器自動(dòng)重新發(fā)現這些服務(wù)器有效,將接下來(lái)的請求重定到這些服務(wù)器實(shí)例上,馬上能提高回應的時(shí)間。
這里用來(lái)發(fā)現集群成員是否有效的機制(ServerUtil)并非是最快的方法。
這個(gè)集群設置的一個(gè)缺陷是它僅僅提供一個(gè)負載均衡器。當用作負載均衡器的 Tomcat 實(shí)例掛起時(shí)會(huì )發(fā)生什么事情呢?就沒(méi)有途徑轉發(fā)請求到集群,這個(gè)結果叫做單點(diǎn)失敗(SPoF).其中一個(gè)解決方法就是有另外一個(gè)Tomcat實(shí)例運行著(zhù),作為一個(gè)備用負載均衡器。如果主負載均衡器崩潰時(shí),備用均衡器將接替它的工作。典型的 高可靠性集群(HA) 包含兩個(gè)負載均衡器防止 SPoF 的情況發(fā)生。
在上面的例子中,所有Tomcat實(shí)例(包括負載均衡器)都是配置在同一臺機器上運行。更好的設置就是在一臺獨立的機器上運行負載均衡器。同樣,限制每臺機器擁有兩個(gè)集群節點(diǎn),充分利用水平縮放的方法來(lái)保證集群的效率。
對J2EE Web 應用服務(wù)器來(lái)講,HTTP session 復制是一種昂貴的操作。J2EE集群環(huán)境下,session管理的實(shí)現應該在項目的分析和設計階段中就需要考慮。編碼時(shí)必須想著(zhù)集群環(huán)境。如果沒(méi)有在設計階段就考慮集群的實(shí)現,為了讓?xiě)媚茉诩涵h(huán)境下工作,代碼可能需要全部重寫(xiě)。這會(huì )造成非常大的影響。
如果web應用支持各種對象緩存機制,那么在應用開(kāi)發(fā)的初始階段,集群環(huán)境中的緩存對象就應該被考慮。這是非常重要的,因為對于提供精確和即時(shí)的事務(wù)數據給Web用戶(hù),在所有集群的節點(diǎn)中保持緩存數據的同步是非常危險的。
一旦J2EE集群成功設置和運行,它的管理和維護將變得非常重要。保持集群的運行和將應用的變化推到所有的集群節點(diǎn)上。需要有一個(gè)方法提供這些服務(wù),實(shí)現一個(gè)監視器服務(wù),周期性的檢測服務(wù)器的有效性,如果集群中有節點(diǎn)無(wú)效,它將會(huì )發(fā)出通知。這個(gè)服務(wù)有規律間隔的檢測失效的節點(diǎn),并從活動(dòng)集群節點(diǎn)列表中刪除失效的節點(diǎn)。它應該擁有一種能力,當改變和更新出現時(shí),它能同步和更新集群中所有的服務(wù)器。由于對web應用的所有的請求必須通過(guò)負載均衡系統,這個(gè)系統能檢測到活動(dòng)session的數量,活動(dòng)session的數量,回應次數,高峰負載的次數,高峰其間活動(dòng)session的數量,低谷其間活動(dòng)負載的數量,等等。這些審計信息可以為提高性能,優(yōu)化整個(gè)系統作為參考。
在這里,可以通過(guò)手動(dòng)調整配置文件(server.xml 和 rules.xml)滿(mǎn)足設置集群和負載均衡器的所有配置需求。如果Jakarta項目組提供基于Web的集群管理工具,那我們就可以通過(guò)使用管理工具修改配置來(lái)管理集群和負載均衡。
+ 資源
*
Tomcat 5 主頁(yè)*
Tomcat 站點(diǎn)的集群主頁(yè)*
Tomcat 站點(diǎn)的負載均衡主頁(yè)*
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