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

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