只需將下列信息放入 或 元素即可實現集群:
上述配置啟用了全局(all-to-all)會話復制功能,全局會話復制是指利用 DeltaManager 來只復制會話中的變更(Session Delta,也譯作“會話增量”)。這里說的“全局”是指:會話變更會被復制到集群中的所有其他節點(指 Tomcat 實例)中。全局復制非常適于小集群,但不建議在大集群(包含很多 Tomcat 節點)上采用這種方法。另外,值得注意的是,當使用 delta manager 時,它會將變更復制到所有的節點上,甚至包括那些根本沒有部署該應用的節點。
為了解決這個問題,你就得使用 BackupManager。它會把會話數據復制給一個指定的備份節點(這種復制也被稱為“配對復制”),而且該備份節點也一定要部署了相關應用。BackupManager 的缺點在于:不像 DeltaManager 那樣久經實踐考驗。
下面是一些重要的默認值。
下面是默認的集群配置:
<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.ClusterSessionListener"/>
</Cluster>
稍后,本文檔將更詳細地闡述這部分的內容。
要想在 Tomcat 8 上運行會話復制,需要執行以下步驟:
負載均衡可以通過多種技術來實現,參看負載均衡部分。
注意:會話狀態是通過 cookie 來記錄的,所以你的 URL 必須保持一致,否則就會創建一個新會話。
注意:當前如要支持集群,需要 JDK 1.5 或更新版本。
集群模塊使用 Tomcat 的 JULI 日志框架,所以可以通過 logging.properties 文件來配置日志。為了跟蹤消息,你可以啟用 org.apache.catalina.tribes.MESSAGES 鍵上的日志。
在 Tomcat 中,可以使用以下方法中的一種啟用會話復制:
在這一版本的 Tomcat 中,可以使用 DeltaManager 執行全局式會話狀態復制,或者使用 BackupManager 執行備份復制,將會話復制到一個節點上。全局式會話復制這種算法只有在集群較小時才比較有效。對于大型集群,更多使用主從會話復制,將會話存儲到一臺配置了 BackupManager 的備份服務器上。
當前可以使用域名 worker 屬性(mod_jk 版本 > 1.2.8)來構建集群分區,從而有可能利用 DeltaManager 實現更具有可擴展性的集群方案(需要為此配置域的攔截器)。為了在全局性環境中降低網絡流量,可以將集群分成幾個較小的分組。為不同的分組使用不同的組播地址即能實現這種方案。下圖展示的是一種簡單的配置方案。
DNS 輪詢
|
負 載 均 衡 器
/ \
集群 1 集群 2
/ \ / \
Tomcat 1 Tomcat 2 Tomcat 3 Tomcat 4
Tomcat集群信息
值得注意的是,使用會話復制僅僅是集群化的一個基礎方案。關于集群的實現,另一個常用的概念是耕種(farming),比如:只需將應用部署到一個服務器上,集群就會將部署分發到整個集群的各個節點中。這都是 FarmWarDeployer 所具有的功能(參看 server.xml 中的集群范例)。
下一節將深入介紹會話復制的工作原理以及配置方式。
通過組播心跳包(heartbeat)建立起成員(Membership)關系,因此,如果希望細分集群,可以改變 <Membership> 元素中的組播 IP 地址或端口。
心跳包中含有 Tomcat 節點的 IP 地址,以及 Tomcat 用來偵聽會話復制流量的 TCP 端口。所有的數據通信都使用了 TCP 協議。
ReplicationValve 用于查找請求結束的時間,如果存在會話復制,就對該復制進行初始化。只復制會話變更的數據(通過在會話上調用 setAttribute 或 removeAttribute 來完成)。
復制的異步與同步模式應該是最值得我們注意的一個特點了。在同步復制模式下,復制的會話通過線纜傳送,重新在所有集群節點上實例化,這樣才會返回請求。同步和異步是通過 channelSendOptions 標志(整型值)來配置的。SimpleTcpCluster/DeltaManager 組合的默認值是 8,從而是異步。詳情可以參考一下 send flag(overview) 或 send flag(javadoc)。在異步復制過程中,請求不必等到數據被復制完畢即可返回。異步復制縮短了請求時間,而同步復制則保證了能在請求返回之前復制完會話。
如果你使用了 mod_jk 而沒有使用粘性會話(sticky session),或者粘性會話由于某種原因而不起作用,或者僅是故障轉移,會話 id 需要修改,因為它之前含有之前 Tomcat 的 worker id(通過 Engine 元素中的 jvmRoute 定義)。為了解決這個問題,就要用到 JvmRouteBinderValve。
JvmRouteBinderValve 將重寫會話 id,以便確保下一個請求在故障轉移后依然能保持粘性(不會因為 worker 不再可用而回滾到某個隨機的節點中)。利用同樣的名字,該值重寫了 cookie 中的 JSESSIONID 值。假如沒有正確地設置 valve,將使 mod_jk 模塊在失敗后很難保持會話的粘性。
記住,如果在 server.xml 中自定義值,那么默認值將不再有效,所以一定要確保添加了默認所定義的值。
提示:
利用屬性 sessionIdAttribute 可以改變包含舊會話 id 的請求屬性名。默認的請求屬性名是:org.apache.catalina.ha.session.JvmRouteOrignalSessionID。
技巧:
可以啟用 mod_jk 翻轉模式在刪除一個節點, 然后啟用了 mod_jk Worker 禁用 JvmRouteBinderValves 。這種用例意味著只有請求的會話才能得到遷移。