上一篇我们介绍了集群通信的原理和配置,本篇我们再来通过官网的例子一起来看一下Tomcat集群通过的过程。
集群工作过程
Tomcat 的官网给出了一个例子,来说明 Tomcat 集群模式下是如何工作的,以及 Tomcat 集群是如何实现高可用的。比如集群由 Tomcat A 和 Tomcat B 两个 Tomcat 实例组成,按照时间先后顺序发生了如下事件:
Tomcat A 启动
Tomcat A 启动过程中,当 Host 对象被创建时,一个 Cluster 组件(默认是 SimpleTcpCluster)被关联到这个 Host 对象。当某个应用在web.xml中设置了 Distributable 时,Tomcat 将为此应用的上下文环境创建一个 DeltaManager。SimpleTcpCluster 启动 Membership 服务和 Replication 服务。
Tomcat B 启动(在 Tomcat A 之后启动)
首先 Tomcat B 会执行和 Tomcat A 一样的操作,然后 SimpleTcpCluster 会建立一个由 Tomcat A 和 Tomcat B 组成的 Membership。接着 Tomcat B 向集群中的 Tomcat A 请求 Session 数据,如果 Tomcat A 没有响应 Tomcat B 的拷贝请求,Tomcat B 会在 60 秒后 time out。在 Session 数据拷贝完成之前 Tomcat B 不会接收浏览器的请求。
Tomcat A 接收 HTTP 请求,创建 Session 1
Tomcat A 响应客户请求,在把结果发送回客户端之前,ReplicationValve 会拦截当前请求(如果 Filter 中配置了不需拦截的请求类型,这一步就不会进行,默认配置下拦截所有请求),如果发现当前请求更新了 Session,就调用 Replication 服务建立 TCP 连接将 Session 拷贝到 Membership 列表中的其他节点即 Tomcat B。在拷贝时,所有保存在当前 Session 中的可序列化的对象都会被拷贝,而不仅仅是发生更新的部分。
Tomcat A 崩溃
当 Tomcat A 崩溃时,Tomcat B 会被告知 Tomcat A 已从集群中退出,然后 Tomcat B 就会把 Tomcat A 从自己的 Membership 列表中删除。并且 Tomcat B 的 Session 更新时不再往 Tomcat A 拷贝,同时负载均衡器会把后续的 HTTP 请求全部转发给 Tomcat B。在此过程中所有的 Session 数据不会丢失。
Tomcat B 接收 Tomcat A 的请求
Tomcat B 正常响应本应该发往 Tomcat A 的请求,因为 Tomcat B 保存了 Tomcat A 的所有 Session 数据。
Tomcat A 重新启动
Tomcat A 按步骤 1、2 操作启动,加入集群,并从 Tomcat B 拷贝所有 Session 数据,拷贝完成后开始接收请求。
Tomcat A 接收请求,Session 1 被用户注销
Tomcat 继续接收发往 Tomcat A 的请求,Session 1 设置为失效。请注意这里的失效并非因为 Tomcat A 处于非活动状态超过设置的时间,而是应用程序执行了注销的操作(比如用户登出)而引起的 Session 失效。这时 Tomcat A 向 Tomcat B 发送一个 Session 1 Expired 的消息,Tomcat B 收到消息后也会把 Session 1 设置为失效。
Tomcat B 接收到一个新请求,创建 Session 2
同理这个新的 Session 也会被拷贝到 Tomcat A。
Tomcat A 上的 Session 2 过期
因超时原因引起的 Session 失效 Tomcat A 无需通知 Tomcat B,Tomcat B 同样知道 Session 2 已经超时。因此对于 Tomcat 集群有一点非常重要,所有节点的操作系统时间必须一致。不然会出现某个节点 Session 已过期而在另一节点此 Session 仍处于活动状态的现象。