web server apache tomcat11-18-clusting 集群
前言
整理这个官方翻译的系列,原因是网上大部分的 tomcat 版本比较旧,此版本为 v11 最新的版本。
开源项目
从零手写实现 tomcat minicat 别称【嗅虎】心有猛虎,轻嗅蔷薇。
系列文章
web server apache tomcat11-01-官方文档入门介绍
web server apache tomcat11-02-setup 启动
web server apache tomcat11-03-deploy 如何部署
web server apache tomcat11-04-manager 如何管理?
web server apache tomcat11-06-Host Manager App -- Text Interface
web server apache tomcat11-07-Realm Configuration
web server apache tomcat11-08-JNDI Resources
web server apache tomcat11-09-JNDI Datasource
web server apache tomcat11-10-Class Loader
...
clusting
急于求成
只需将以下内容添加到您的 <Engine>
或 <Host>
元素中即可启用集群。
使用上述配置将启用所有节点间的会话复制,使用 DeltaManager 复制会话增量。所谓的全对全,是指每个会话都会复制到集群中的所有其他节点。这在较小的集群中效果很好,但我们不建议在较大的集群中使用 — 多于 4 个节点左右。此外,当使用 DeltaManager 时,Tomcat 将会话复制到所有节点,甚至那些未部署应用的节点。
为了解决这些问题,您将希望使用 BackupManager。BackupManager 仅将会话数据复制到一个备用节点,并且仅复制到已部署应用的节点。一旦您使用 DeltaManager 运行了简单的集群,随着您增加集群中节点的数量,您可能希望迁移到 BackupManager。
以下是一些重要的默认值:
- 多播地址为 228.0.0.4
- 多播端口为 45564(端口和地址一起确定了集群成员身份)
- 广播的 IP 是 java.net.InetAddress.getLocalHost().getHostAddress()(确保不要广播 127.0.0.1,这是一个常见的错误)
- 监听复制消息的 TCP 端口是范围在 4000-4100 的第一个可用服务器套接字
- 配置了监听器 ClusterSessionListener
- 配置了两个拦截器 TcpFailureDetector 和 MessageDispatchInterceptor
以下是默认的集群配置:
<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>
我们将在本文档后面更详细地介绍这一部分。
安全性
集群实现是基于在所有集群相关的网络流量中使用安全、可信任的网络的前提下编写的。在不安全、不可信任的网络上运行集群是不安全的。
为 Tomcat 集群提供安全、可信任的网络有许多选项,包括:
- 私有 LAN
- 虚拟专用网络(VPN)
- IPSEC
EncryptInterceptor 提供了机密性和完整性保护,但它不能保护免受在不可信任网络上运行 Tomcat 集群时可能发生的所有风险,特别是 DoS 攻击。
集群基础知识
要在您的 Tomcat 11 容器中运行会话复制,应完成以下步骤:
- 所有会话属性都必须实现 java.io.Serializable
- 在 server.xml 中取消注释 Cluster 元素
- 如果您定义了自定义集群阀门,请确保在 server.xml 中的 Cluster 元素下也定义了 ReplicationValve
- 如果您的 Tomcat 实例运行在同一台机器上,请确保 Receiver.port 属性对于每个实例是唯一的,在大多数情况下,Tomcat 能够自动检测到范围在 4000-4100 的可用端口
- 确保您的 web.xml 中有
<distributable/>
元素 - 如果您使用 mod_jk,请确保在 Engine
<Engine name="Catalina" jvmRoute="node01" >
中设置了 jvmRoute 属性,并且该 jvmRoute 属性值与 workers.properties 中的 worker 名称匹配 - 确保所有节点具有相同的时间并与 NTP 服务同步!
- 确保您的负载均衡器配置为粘性会话模式
负载均衡可以通过多种技术实现,如负载均衡章节所述。
注意:请记住,您的会话状态由 cookie 跟踪,因此您的 URL 在外部必须看起来相同,否则会创建一个新的会话。
集群模块使用 Tomcat JULI 日志框架,因此您可以通过常规的 logging.properties 文件配置日志记录。要跟踪消息,您可以在键 org.apache.catalina.tribes.MESSAGES 上启用日志记录。
概述
为了在 Tomcat 中启用会话复制,可以采取三种不同的路径来实现相同的目标:
- 使用会话持久性,并将会话保存到共享文件系统(PersistenceManager + FileStore)
- 使用会话
持久性,并将会话保存到共享数据库(PersistenceManager + JDBCStore)
- 使用内存复制,使用随 Tomcat 一起提供的 SimpleTcpCluster(lib/catalina-tribes.jar + lib/catalina-ha.jar)
Tomcat 可以使用 DeltaManager 执行会话状态的全对全复制,也可以使用 BackupManager 执行仅将会话复制到一个节点的备份复制。全对全复制是一种仅在集群较小时才有效的算法。对于较大的集群,您应该使用 BackupManager,以使用主要 - 次要会话复制策略,其中会话仅存储在一个备份节点上。
目前,您可以使用 domain worker 属性(mod_jk > 1.2.8)构建具有更高可伸缩性的集群解决方案,以使用 DeltaManager 配置域拦截器(您将需要为此配置域拦截器)。为了在全对全环境中减少网络流量,在多个组之间拆分集群。这可以通过为不同的组使用不同的多播地址轻松实现。一个非常简单的设置如下所示:
DNS 轮询
|
负载均衡器
/ \
集群1 集群2
/ \ / \
Tomcat1 Tomcat2 Tomcat3 Tomcat4
这里重要提及的是,会话复制只是集群的开始。用于实现集群的另一个流行概念是 farming,即将应用程序仅部署到一个服务器,然后集群将在整个集群中分布部署。这是 FarmWarDeployer 可以实现的所有功能(请参阅 server.xml 中的集群示例)。
在下一节中,我们将更深入地介绍会话复制的工作原理和配置方法。
集群信息
通过多播心跳建立成员资格。因此,如果您希望将您的集群细分,可以通过更改 <Membership>
元素中的多播 IP 地址或端口来实现。
心跳包包含 Tomcat 节点的 IP 地址和 Tomcat 用于复制流量的 TCP 端口。所有数据通信都在 TCP 上进行。
ReplicationValve 用于在请求完成后查找并启动复制(如果有)。仅当会话已更改(通过对会话调用 setAttribute 或 removeAttribute)时,才会复制数据。
其中一个最重要的性能考虑因素是同步与异步复制。在同步复制模式下,请求在复制的会话通过网络并在所有其他集群节点上重新实例化之前不会返回。同步与异步是通过 channelSendOptions 标志进行配置的,它是一个整数值。SimpleTcpCluster/DeltaManager 组合的默认值为 8,即异步。有关各种 channelSendOptions 值的更多讨论,请参阅配置参考。
为方便起见,channelSendOptions 可以通过名称设置,而不是整数值,这些名称在启动时将被翻译为其整数值。有效的选项名称为:"asynchronous"(别名 "async"),"byte_message"(别名 "byte"),"multicast","secure","synchronized_ack"(别名 "sync"),"udp","use_ack"。使用逗号分隔多个名称,例如,传递 "async, multicast" 作为选项 SEND_OPTIONS_ASYNCHRONOUS | SEND_OPTIONS_MULTICAST。
您可以在send flag(overview) 或 send flag(javadoc) 上阅读更多关于 send flag 的信息。在异步复制期间,请求在数据被复制之前返回。异步复制可缩短请求时间,而同步复制可确保在请求返回之前复制会话。
在崩溃后将会话绑定到故障转移节点
如果您正在使用 mod_jk 并且未使用粘性会话,或者由于某些原因粘性会话不起作用,或者您只是在故障转移,那么会话 ID 将需要修改,因为它先前包含了前一个 Tomcat 的 worker ID(由 Engine 元素中的 jvmRoute 定义)。为解决此问题,我们将使用 JvmRouteBinderValve。
JvmRouteBinderValve 会重写会话 ID,以确保下一个请求在故障转移后仍然保持粘性(并且不会退回到随机节点,因为该 worker 不再可用)。该阀门将在 cookie 中将 JSESSIONID 值重写为同名。如果没有这个阀门,那么在 mod_jk 模块发生故障时确保粘性会变得更加困难。
请注意,如果您在 server.xml 中添加了自定义阀门,则默认值将不再有效,请确保您添加了所有适当的阀门,这些阀门由默认定义。
提示:
通过属性 sessionIdAttribute,您可以更改包含旧会话 ID 的请求属性名称。默认属性名称为 org.apache.catalina.ha.session.JvmRouteOriginalSessionID。
技巧:
您可以在将节点丢弃到所有备用节点之前通过 JMX 启用此 mod_jk 转换模式!将 JvmRouteBinderValve 备份的 enable 属性设置为 true,禁用 mod_jk 中的 worker,然后丢弃节点并重新启动它!然后再次启用 mod_jk Worker 并禁用 JvmRouteBinderValves。这种用法意味着仅迁移请求的会话。