<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>
下面来仔细剖析一下这段代码。
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"channelSendOptions="6">
Cluster 是主要元素,可在该元素内配置所有的集群相关细节。 对于 SimpleTcpCluster 类或者调用 SimpleTcpCluster.send 方法的对象,它们所发出的每一个消息上都附加着一个 channelSendOptions 标志。关于发送标志的描述可参见我们的 javadoc 文档。DeltaManager 使用 SimpleTcpCluster.send 方法发送信息,而备份管理器则直接通过 channel 来发送自身。
<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"/>
-->
如果在 元素中没有定义 manager,则以上可当做 manager 的配置模板。在 Tomcat 5.x 时期,每个标识为可分发(distributable)的 Web 应用都必须使用同样的 manager,而如今不同了,我们可以为每个应用定义一个 manager 类,从而在集群中混合多个 manager。显然,A 节点上的某个应用的所有 manager 必须与 B 节点上的同样应用的 manager 相同。如果没有为应用指定 manager,而且该应用被标识为 ,Tomcat 就会采取这种 manager 配置,创建一个克隆该配置的 manager 实例。
Channel 元素是 Tribes 架构的一个重要组成部分,Tribes 是 Tomcat 内部所使用的分组通信架构。Channel 元素封装了所有通信相关事项以及成员逻辑。
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
成员关系(Membership)是通过组播来实现的。注意,如果你想将成员扩展到组播范围之外的某个点时,Tribes 现在已经能够支持使用 StaticMembershipInterceptor 的静态成员。address 属性是所用的组播地址,port 是所用的组播端口号。这两项组合起来将集群隔离开。如果你希望一个 QA 集群和一个生产集群,最简单的方法就是将 QA 集群的组播地址和端口号不同于生产集群的组播地址和端口号组合。
成员组件将其自身的 TCP 地址和端口广播到其他节点处,从而使节点间的通信都可以通过 TCP 协议来完成。请注意被广播的 TCP 地址正是 Receiver.address 属性值。
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver
"address="auto"port="5000"selectorTimeout="100"maxThreads="6"/>
在 Tribes 架构中,数据的发送与接收以及被拆分为两种功能性组件了。正如其名所示,Receiver 负责接收信息。由于 Tribes 与线程无关(其他架构也开始采用这一种常见改进了),该组件内部包含一个线程池,设定有 maxThreads 和 minThreads 两种参数。
address 参数值是主机地址,由成员组件广播到其他节点中。
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
Sender 组件负责将消息发送给其他节点。Sender 含有一个 shell 组件 ReplicationTransmitter,但真正所要完成的任务则是通过子组件 Transport 来完成的。由于 Tribes 支持一个 Sender 池,所以消息可以做到同步;如果使用的是 NIO Sender,你也可以并发地发送消息。
并发(Concurrently)意味着将同时有多个发送者对应着一条消息,并行(Parallel)则意味着同时有多个消息对应着多个发送者。
<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 利用了一个堆栈传送消息。每个堆栈内的元素都被称为拦截器,跟 Tomcat 容器中的 valve 的作用差不多。使用拦截器,逻辑可被分成更容易管理的代码段。上面配置中的拦截器:
请注意,拦截器的顺序很重要。在 server.xml 中定义的顺序正是它们出现在 channel 堆栈中的顺序。这种机制就像是链表,最前面的是第一个拦截器,末尾的是最后一个拦截器。
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>
集群使用 valve 来跟踪针对 Web 应用的请求。我们之前已经提到过 ReplicationValve 和 JvmRouteBinderValve。 元素本身并不是 Tomcat 管道的一部分,集群将 valve 添加到了它的父容器上,比如说 元素被配置到 元素中,那么 valve 就会被加到 元素中。
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
默认的 Tomcat 集群支持耕种部署(farmed deployment),比如说集群可以在其他的节点上部署和取消部署应用。该组件的状态目前还不稳定,但我们很快就会解决这个问题。Tomcat 5.0 和 5.5 版本相比,在部署算法上有一点变化。组件的逻辑改变到部署目录必须与应用目录相匹配。
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
因为 SimpleTcpCluster 本身既是 Channel 对象的发送者,又是接受者,所以组件可以将它们自身注册成SimpleTcpCluster 的侦听器。 上面这个侦听器 ClusterSessionListener 将侦听 DeltaManager 复制的消息,并将会话变更应用到 manager 上,反过来应用到会话上。