Tomca教程
Tomcat Manager
Tomcat Realm 配置
Tomcat 安全管理
Tomcat JNDI 资源
Tomcat JDBC 数据源
Tomcat 类加载机制
Tomcat JSPs
Tomcat SSL/TLS配置
Tomcat SSI
Tomcat CGI
Tomcat 代理支持
Tomcat MBean 描述符
Tomcat 默认 Servlet
Tomcat 集群
Tomcat 连接器
Tomcat监控与管理
Tomcat 日志机制
Tomcat 基于 APR 的原生库
Tomcat 虚拟主机
Tomcat 高级 IO 机制
Tomcat 附加组件
Tomcat 安全性注意事项
Tomcat Windows 服务
Tomcat Windows 认证
Tomcat 的 JDBC 连接池
Tomcat WebSocket 支持
Tomcat 重写机制

Tomcat 集群

Tomcat快速入门

只需将下列信息放入  或  元素即可实现集群:

上述配置启用了全局(all-to-all)会话复制功能,全局会话复制是指利用 DeltaManager 来只复制会话中的变更(Session Delta,也译作“会话增量”)。这里说的“全局”是指:会话变更会被复制到集群中的所有其他节点(指 Tomcat 实例)中。全局复制非常适于小集群,但不建议在大集群(包含很多 Tomcat 节点)上采用这种方法。另外,值得注意的是,当使用 delta manager 时,它会将变更复制到所有的节点上,甚至包括那些根本没有部署该应用的节点。

为了解决这个问题,你就得使用 BackupManager。它会把会话数据复制给一个指定的备份节点(这种复制也被称为“配对复制”),而且该备份节点也一定要部署了相关应用。BackupManager 的缺点在于:不像 DeltaManager 那样久经实践考验。

下面是一些重要的默认值。

  1. IP 组播地址为:228.0.0.4
  2. IP 组播端口为:45564(端口和地址一起确定了集群成员)。
  3. 广播的 IP 是 java.net.InetAddress.getLocalHost().getHostAddress()(你一定不能广播 127.0.0.1,这是一个常见错误。)
  4. 侦听复制信息的 TCP 端口是在 4000 - 4100 之间遇到的第一个能用的服务器套接字。
  5. 两个侦听器都配置有 ClusterSessionListener。
  6. 两个拦截器都配置有 TcpFailureDetector 和 MessageDispatch15Interceptor。

下面是默认的集群配置:

  <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集群基本知识

要想在 Tomcat 8 上运行会话复制,需要执行以下步骤:

  • 所有的会话属性必须实现 java.io.Serializable。
  • 在 server.xml 中取消注释 Cluster 元素。
  • 如果你已经定义了自定义集群值,确保在 server.xml 中的 Cluster 元素下面也定义了 ReplicationValve。
  • 如果你的多个 Tomcat 实例都运行在同一台机器上,则要确保每个实例都具有唯一的 tcpListenPort。通常 Tomcat 会自行解决这个问题,会在 4000 - 4100 上自动侦测可用的端口。
  • 确保 web.xml 含有  属性。
  • 如果使用 mod_jk,则要确保在  上设定 jvmRoute 属性。jvmRoute 属性值必须匹配 workers.properties 中的 worker 名称。
  • 所有的节点必须具有相同的时间,并且与 NTP 服务器同步。
  • 确保负载均衡配置了会话模式.

负载均衡可以通过多种技术来实现,参看负载均衡部分。

注意:会话状态是通过 cookie 来记录的,所以你的 URL 必须保持一致,否则就会创建一个新会话。

注意:当前如要支持集群,需要 JDK 1.5 或更新版本。

集群模块使用 Tomcat 的 JULI 日志框架,所以可以通过 logging.properties 文件来配置日志。为了跟踪消息,你可以启用 org.apache.catalina.tribes.MESSAGES 键上的日志。

概述

在 Tomcat 中,可以使用以下方法中的一种启用会话复制:

  1. 使用会话持久性,将会话保存到共享文件系统中(PersistenceManager + FileStore)。
  2. 使用会话持久性,将会话保存到共享数据库中(PersistenceManager + JDBCStore)。
  3. 使用内存复制,使用 Tomcat 自带的 SimpleTcpCluster(lib/catalina-tribes.jar + lib/catalina-ha.jar)。

在这一版本的 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 。这种用例意味着只有请求的会话才能得到迁移。