本文意在介紹對tomcat集羣進行更深入詳細的配置以滿足特定需求。
對於WEB應用集羣的技術實現而言,最大的難點就是如何能在集羣中的多個節點之間保持數據的一致性,會話(Session)信息是這些數據中最重要的一塊。
要實現這一點,大體上有兩種方式,
一種是把所有Session數據放到一臺服務器上或者數據庫中,集羣中的所有節點通過訪問這臺Session服務器來獲取數據;
另一種就是在集羣中的所有節點間進行Session數據的同步拷貝,任何一個節點均保存了所有的Session數據。
兩種方式都各有優點,
第一種方式簡單、易於實現,但是存在着Session服務器發生故障會導致全系統不能正常工作的風險;
第二種方式可靠性更高,任一節點的故障不會對整個系統對客戶訪問的響應產生影響,但是技術實現上更復雜一些。
常見的平臺或中間件如microsoft asp.net和IBM WAS都會提供對兩種共享方式的支持,tomcat也是這樣,但是一般採用第二種方式。
當採用tomcat默認集羣配置(<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>)時,配置的細節實際上被省略了,
對於大多數應用而言,使用默認配置已經足夠,完整的默認配置應該是這樣:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
下面筆者對這裏的配置項作詳細解釋,以下內容均是筆者閱讀了tomcat官方文檔後自己的理解,有些可能不對,希望讀者能帶着批判的眼光閱讀,並歡迎指正筆者錯誤。
tomcat集羣各節點通過建立tcp鏈接來完成Session的拷貝,拷貝有同步和異步兩種模式。
在同步模式下,對客戶端的響應必須在Session拷貝到其他節點完成後進行;
異步模式無需等待Session拷貝完成就可響應。
異步模式更高效,但是同步模式可靠性更高。同步異步模式由channelSendOptions參數控制,默認值是8,爲異步模式,4是同步模式。
在異步模式下,可以通過加上拷貝確認(Acknowledge)來提高可靠性,此時channelSendOptions設爲10。
Manager用來在節點間拷貝Session,默認使用DeltaManager,DeltaManager採用的一種all-to-all的工作方式,
即集羣中的節點會把Session數據向所有其他節點拷貝,而不管其他節點是否部署了當前應用。
當集羣中的節點數量很多並且部署着不同應用時,可以使用BackupManager,BackManager僅向部署了當前應用的節點拷貝Session。
但是到目前爲止BackupManager並未經過大規模測試,可靠性不及DeltaManager。
Channel負責對tomcat集羣的IO層進行配置。Membership用於發現集羣中的其他節點,
這裏的address用的是組播地址(Multicast address,瞭解更多組播地址詳情請參見http://zyycaesar.iteye.com/admin/blogs/296501),
使用同一個組播地址和端口的多個節點同屬一個子集羣,因此通過自定義組播地址和端口就可將一個大的tomcat集羣分成多個子集羣。
Receiver用於各個節點接收其他節點發送的數據,在默認配置下tomcat會從4000-4100間依次選取一個可用的端口進行接收,
自定義配置時, 如果多個tomcat節點在一臺物理服務器上注意要使用不同的端口。
Sender用於向其他節點發送數據,具體實現通過Transport配置,
PooledParallelSender是從tcp連接池中獲取連接,可以實現並行發送,即集羣中的多個節點可以同時向其他所有節點發送數據而互不影響。
Interceptor有點類似下面將要解釋的Valve,起到一個閥門的作用,在數據到達目的節點前進行檢測或其他操作,如TcpFailureDetector用於檢測在數據的傳輸過程中是否發生了tcp錯誤。
關於Channel的編程模型,請參見http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/tribes/Channel.html。
Valve用於在節點向客戶端響應前進行檢測或進行某些操作,
ReplicationValve就是用於用於檢測當前的響應是否涉及Session數據的更新,如果是則啓動Session拷貝操作,filter用於過濾請求,如客戶端對圖片,css,js的請求就不會涉及Session,
因此不需檢測,默認狀態下不進行過濾,監測所有的響應。
JvmRouteBinderValve會在前端的Apache mod_jk發生錯誤時保證同一客戶端的請求發送到集羣的同一個節點,
tomcat官方文檔並未解釋如何實現這一點,而且筆者認爲這一設置似乎並無多大實用性。
Deployer用於集羣的farm功能,監控應用中文件的更新,以保證集羣中所有節點應用的一致性,
如某個用戶上傳文件到集羣中某個節點的應用程序目錄下,Deployer會監測到這一操作並把這一文件拷貝到集羣中其他節點相同應用的對應目錄下以保持所有應用的一致。
這是一個相當強大的功能,不過很遺憾,tomcat集羣目前並不能做到這一點,開發人員正在努力實現它,這裏的配置只是預留了一個接口。
Listener用於跟蹤集羣中節點發出和收到的數據,也有點類似Valve的功能。
在大體瞭解了tomcat集羣實現模型後,就可以對集羣作出更優化的配置了,
tomcat推薦了一套配置,使用了比DeltaManager更高效的BackupManager,並且對ReplicationValve設置了請求過濾,
注意在一臺服務器部署多個節點時需要修改Receiver的偵聽端口,另外,爲了更高效的在節點間拷貝數據,所有tomcat節點最好採用相同的配置,
具體配置如下: