只需将下列信息放入 或 元素即可实现集群:
上述配置启用了全局(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 。这种用例意味着只有请求的会话才能得到迁移。