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

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
