<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="6">
<Manager className="org.apache.catalina.ha.session.BackupManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"
mapSendOptions="6"/>
<!--
<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="5000"
selectorTimeout="100"
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"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>
<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>
下面來(lái)仔細(xì)剖析一下這段代碼。
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"channelSendOptions="6">
Cluster 是主要元素,可在該元素內(nèi)配置所有的集群相關(guān)細(xì)節(jié)。 對(duì)于 SimpleTcpCluster 類或者調(diào)用 SimpleTcpCluster.send 方法的對(duì)象,它們所發(fā)出的每一個(gè)消息上都附加著一個(gè) channelSendOptions 標(biāo)志。關(guān)于發(fā)送標(biāo)志的描述可參見(jiàn)我們的 javadoc 文檔。DeltaManager 使用 SimpleTcpCluster.send 方法發(fā)送信息,而備份管理器則直接通過(guò) channel 來(lái)發(fā)送自身。
<Manager className="org.apache.catalina.ha.session.BackupManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"
mapSendOptions="6"/>
<!--
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
-->
如果在 元素中沒(méi)有定義 manager,則以上可當(dāng)做 manager 的配置模板。在 Tomcat 5.x 時(shí)期,每個(gè)標(biāo)識(shí)為可分發(fā)(distributable)的 Web 應(yīng)用都必須使用同樣的 manager,而如今不同了,我們可以為每個(gè)應(yīng)用定義一個(gè) manager 類,從而在集群中混合多個(gè) manager。顯然,A 節(jié)點(diǎn)上的某個(gè)應(yīng)用的所有 manager 必須與 B 節(jié)點(diǎn)上的同樣應(yīng)用的 manager 相同。如果沒(méi)有為應(yīng)用指定 manager,而且該應(yīng)用被標(biāo)識(shí)為 ,Tomcat 就會(huì)采取這種 manager 配置,創(chuàng)建一個(gè)克隆該配置的 manager 實(shí)例。
Channel 元素是 Tribes 架構(gòu)的一個(gè)重要組成部分,Tribes 是 Tomcat 內(nèi)部所使用的分組通信架構(gòu)。Channel 元素封裝了所有通信相關(guān)事項(xiàng)以及成員邏輯。
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
成員關(guān)系(Membership)是通過(guò)組播來(lái)實(shí)現(xiàn)的。注意,如果你想將成員擴(kuò)展到組播范圍之外的某個(gè)點(diǎn)時(shí),Tribes 現(xiàn)在已經(jīng)能夠支持使用 StaticMembershipInterceptor 的靜態(tài)成員。address 屬性是所用的組播地址,port 是所用的組播端口號(hào)。這兩項(xiàng)組合起來(lái)將集群隔離開(kāi)。如果你希望一個(gè) QA 集群和一個(gè)生產(chǎn)集群,最簡(jiǎn)單的方法就是將 QA 集群的組播地址和端口號(hào)不同于生產(chǎn)集群的組播地址和端口號(hào)組合。
成員組件將其自身的 TCP 地址和端口廣播到其他節(jié)點(diǎn)處,從而使節(jié)點(diǎn)間的通信都可以通過(guò) TCP 協(xié)議來(lái)完成。請(qǐng)注意被廣播的 TCP 地址正是 Receiver.address 屬性值。
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver
"address="auto"port="5000"selectorTimeout="100"maxThreads="6"/>
在 Tribes 架構(gòu)中,數(shù)據(jù)的發(fā)送與接收以及被拆分為兩種功能性組件了。正如其名所示,Receiver 負(fù)責(zé)接收信息。由于 Tribes 與線程無(wú)關(guān)(其他架構(gòu)也開(kāi)始采用這一種常見(jiàn)改進(jìn)了),該組件內(nèi)部包含一個(gè)線程池,設(shè)定有 maxThreads 和 minThreads 兩種參數(shù)。
address 參數(shù)值是主機(jī)地址,由成員組件廣播到其他節(jié)點(diǎn)中。
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
Sender 組件負(fù)責(zé)將消息發(fā)送給其他節(jié)點(diǎn)。Sender 含有一個(gè) shell 組件 ReplicationTransmitter,但真正所要完成的任務(wù)則是通過(guò)子組件 Transport 來(lái)完成的。由于 Tribes 支持一個(gè) Sender 池,所以消息可以做到同步;如果使用的是 NIO Sender,你也可以并發(fā)地發(fā)送消息。
并發(fā)(Concurrently)意味著將同時(shí)有多個(gè)發(fā)送者對(duì)應(yīng)著一條消息,并行(Parallel)則意味著同時(shí)有多個(gè)消息對(duì)應(yīng)著多個(gè)發(fā)送者。
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
</Channel>
Tribes 利用了一個(gè)堆棧傳送消息。每個(gè)堆棧內(nèi)的元素都被稱為攔截器,跟 Tomcat 容器中的 valve 的作用差不多。使用攔截器,邏輯可被分成更容易管理的代碼段。上面配置中的攔截器:
請(qǐng)注意,攔截器的順序很重要。在 server.xml 中定義的順序正是它們出現(xiàn)在 channel 堆棧中的順序。這種機(jī)制就像是鏈表,最前面的是第一個(gè)攔截器,末尾的是最后一個(gè)攔截器。
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>
集群使用 valve 來(lái)跟蹤針對(duì) Web 應(yīng)用的請(qǐng)求。我們之前已經(jīng)提到過(guò) ReplicationValve 和 JvmRouteBinderValve。 元素本身并不是 Tomcat 管道的一部分,集群將 valve 添加到了它的父容器上,比如說(shuō) 元素被配置到 元素中,那么 valve 就會(huì)被加到 元素中。
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
默認(rèn)的 Tomcat 集群支持耕種部署(farmed deployment),比如說(shuō)集群可以在其他的節(jié)點(diǎn)上部署和取消部署應(yīng)用。該組件的狀態(tài)目前還不穩(wěn)定,但我們很快就會(huì)解決這個(gè)問(wèn)題。Tomcat 5.0 和 5.5 版本相比,在部署算法上有一點(diǎn)變化。組件的邏輯改變到部署目錄必須與應(yīng)用目錄相匹配。
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
因?yàn)?nbsp;SimpleTcpCluster 本身既是 Channel 對(duì)象的發(fā)送者,又是接受者,所以組件可以將它們自身注冊(cè)成SimpleTcpCluster 的偵聽(tīng)器。 上面這個(gè)偵聽(tīng)器 ClusterSessionListener 將偵聽(tīng) DeltaManager 復(fù)制的消息,并將會(huì)話變更應(yīng)用到 manager 上,反過(guò)來(lái)應(yīng)用到會(huì)話上。