Tomcat 入门实战(4)--Tomcat 集群 Session 复制

发布时间 2023-04-02 10:13:18作者: 且行且码

本文主要介绍在 Tomcat 集群中如何进行 Session 复制,文中所使用到的软件版本:Centos 7.9.2009、Java 1.8.0_321、Tomcat 8.5.87。

1、快速配置

取消 conf/server.xml 文件中的以下注释来启用集群:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

使用上述配置将启用 all-to-all 会话复制,它使用 DeltaManager 进行会话增量复制。all-to-all 意味着每个会话都将被复制到群集中的所有其他节点。这对于较小的集群非常有效,但不建议在大型集群(超过4个节点左右)中使用它。此外,当使用 DeltaManage r时,Tomcat 将会话复制到所有节点,甚至是没有部署该应用程序的节点。
为了解决这些问题,您将需要使用 BackupManager。BackupManager 仅将会话数据复制到一个备份节点,并且仅复制到已部署该应用程序的节点。一旦您使用 DeltaManage r运行了一个简单的集群,您可能希望随着增加集群中节点的数量而迁移到 BackupManager。

上述配置对应的详细默认配置如下:

<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.MessageDispatchInterceptor"/>
  </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>

以下是一些重要的默认值:
1、组播地址为 228.0.0.4
2、组播端口为 45564(端口和地址一起确定集群成员身份)
3、广播的 IP 是 java.net.InetAddress.getLocalHost().getHostAddress()(确保不要广播127.0.0.1,这是一个常见错误)
4、用于监听复制消息的 TCP 端口是在 4000-4100 范围内第一个可用的服务器套接字
5、侦听器配置为 ClusterSessionListener
6、配置了两个拦截器 TcpFailureDetector 和 MessageDispatchInterceptor

2、Session 复制实现步骤

1、所有会话属性必须实现 java.io.Serializable 接口。
2、在 conf/server.xml 文件中取消注释 Cluster 元素。
3、如果您定义了自定义集群阀门,请确保在 conf/server.xml 文件的 Cluster 元素下也定义了 ReplicationValve。
4、如果 Tomcat 实例在同一台机器上运行,确保每个实例的 Receiver.port 属性是唯一的。在大多数情况下,Tomcat 可以通过自动检测 4000-4100 范围内可用端口来解决此问题。
5、确保应用的 web.xml 具有 <distributable/> 元素。
6、如果使用 mod_jk,请确保在 Engine(<Engine name="Catalina" jvmRoute="node01">) 中设置 jvmRoute 属性,并且 jvmRoute 属性值与 workers.properties 中的 worker 名称匹配。
7、确保所有节点具有相同的时间并与 NTP 服务同步.
8、确保负载均衡器配置为粘性会话模式。

3、实际操作

3.1、规划

IP 端口 用途
10.49.196.10 8080 Tomcat1
10.49.196.11 8080 Tomcat2
10.49.196.13 8080 反向代理(Nginx)

3.2、修改 server.xml

取消 Tomcat 中 conf/server.xml 文件的以下注释:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

3.3、添加 <distributable/>

这里直接使用 Tomcat 自带的应用 ROOT 做测试,在 webapps/ROOT/WEB-INF/web.xml 文件中增加 <distributable/>:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="true">

  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>
  <distributable/>
</web-app>

3.4、添加测试页面

新增 webapps/ROOT/index2.jsp 文件:

<body>
SessionID:<%=session.getId()%>
<br>
SessionIP:<%=request.getLocalAddr()%>
<br>
SessionPort:<%=request.getLocalPort()%>
</body>

3.5、配置反向代理

Nginx 的配置如下:

upstream tomcat {
  server 10.49.196.30:8080;
  server 10.49.196.31:8080;
}

server {
  listen 7070;
  server_name  localhost;
  
  location / {
    proxy_pass  http://tomcat;
  }
}

3.6、测试

启动两个 Tomcat 及 Nginx,访问代理页面:

 

多次访问代理页面,可以看到 IP 不停的变化,但 SessionID 不变,说明 Session 复制有效。

 

 

参考:https://tomcat.apache.org/tomcat-8.5-doc/cluster-howto.html