tomcat集群session的复制和实现
问:跨服务器tomcat集群是如何才能实现session共享的,sessionID是存放在每个tomcat中,怎么关联?Apache Tomcat 5.5 Servlet/JSP 容器怎样配制集群?session复制是怎样实现的,以及怎样配置它?
要在Tomcat 5.5容器里进行session复制,必须完成下列步骤:
所有会话属性值必须实现java.io.Serializable
把server.xml文件里的群集(Cluster)元素的注释取消(Uncomment)
把server.xml文件里的Valve(ReplicationValve)元素注释取消(Uncomment)
如果有多个Tomcat实例在一台机器上运行,确保每个实例的tcpListenPort属性值是不冲突的。
确定 web.xml 中含有 <distributable/> 元素, 或者设置 <Context distributable="true" />
确定设置好Engine元素的 jvmRoute 的属性值: <Engine jvmRoute="node01" >
确定所有节点拥有相同的时间, 并且通过网络时间服务(NTP)同步操作系统的时间!
确定负载均衡器已经配置为黏性会话模式.
注意:记住你的会话状态是被一个cookie跟踪的,所以你的URL从外面看必须是相同的,否则一个新的session就会被产生。
注意:集群支持目前需要JDK 1.4或其后版本。
要在Tomcat里实现会话session复制,下面三种方法都可以实现相同效果:
使用session 持久化, 并将 session 保存到一个共享的文件系统(持久管理器 + 文件存储)
使用session 持久化, 并将 session 保存到一个共享的 数据库 (持久管理器 + JDBC存储)
使用in-memory-replication,使用和Tomcat 5自带的SimpleTcpCluster(server/lib/catalina-cluster.jar)
应用场景:
在这个场景中,计划使用两个tomcat 实例 TomcatA 和 TomcatB. 我们将覆盖下面连续的事件:
TomcatA 接受一个请求,session S1 被产生,TomcatB 接受一个session S1的请求 ,TomcatA 接受一个请求,session ( S1 )失效。 TomcatB 接受一个新的session ( S2 )的请求。 TomcatA 因为没有活动session S2过期失效。
在session复制时代码里发生的所有事情
1)Tomcat 标准方式启动
当 Host 对象被创建之后, 一个 cluster 对象与它关联. 当上下文被解析完, 如果 web.xml中有distributable元素, Tomcat 通过 Cluster class (in this case SimpleTcpCluster)为支持复制的上下文创建一个管理器. 因此通过设置web.xml中的distributable来启用集群。 Tomcat 将为上下文创建 DeltaManager莱取代 StandardManager. cluster class 将启动 a membership service (multicast) 和 a replication service (tcp unicast). More on the architecture further down in this document.
2)TomcatB 启动
当TomcatB启动时,除了一个例外以外,它按照TomcatA一样的顺序启动。群集被启用,并将建立一组会员(TomcatA,TomcatB)。TomcatB现在将要request已经存在于群集里的服务器的会话状态,在这里这个服务器是TomcatA。TomcatA回应TomcatB的请求,并且在TomcatB开始为HTTP requests监听之前,这个状态已经由TomcatA传递给TomcatB了。在TomcatA不回应的情况下,TomcatB在60秒后中断,并发出一个日志记录。对于每个已经分布在web.xml里的web应用程序,会话状态会被转移。注意:要有效地使用会话复制,你的所有tomcat实例要配置成一样的。
3)TomcatA 接受一个请求,session S1 被产生。
TomcatA对待传递来的请求与对待没有会话复制一样。当请求完成以后,活动就开始了,ReplicationValve在回应被返回到用户那里之前会截断这个请求。在这时,它发现会话被修改过,它就用TCP把这个会话复制给TomcatB。一旦这个分段的数据被递交给操作系统TCP logic,请求就通过valve pipeline返回给用户。对于每个请求,整个会话都被复制,这允许在不调用setAttribute 或 removeAttribute情况下,在会话中修改属性的代码被复制。配置参数useDirtyFlag可以被用来优化会话复制的次数。
4)TomcatA崩溃
当TomcatA崩溃时,TomcatB会收到通知说TomcatA已经退出群集。TomcatB把TomcatA从它的会员列单中删除掉,TomcatB里有任何更改也不会再通知TomcatA。装载均衡器会把对TomcatA的请求引向TomcatB以及所有当前活动会话。
5)TomcatB 接受一个session S1的请求
TomcatB像处理其他任何请求一样处理这个请求。
TomcatA启动时,在它接受新的请求以及让它自己可被使用之前,它要按照上面 1) 2)中所描述的顺序进行启动。它会加入群集,与TomcatB联系,了解所有会话的当前状态。一旦它接受到会话状态,它就完成装载并打开它的HTTP/mod_jk ports。所以在TomcatA接受到来自TomcatB的会话状态之前,不会对它发出请求。
6)TomcatA 接受一个请求,session ( S1 )失效。
失效的呼叫被拦截,这个会话就加入到失效的会话行列。在这个请求完成以后,它向TomcatB发出一个"expire"信息,TomcatB也把这个会话变为失效。
7)TomcatB 接受一个新的session ( S2 )的请求。
与步骤3)情形一样。
8)TomcatA 因为没有活动session S2过期失效。
就如一个会话由用户让它无效一样,invalidate呼叫被拦截到,这个会话就加入失效的会话行列。这一点上,除非另一个请求通过系统来检查失效行列,会话失效不会在其他地方重复。
Phuuuhh! :)
Membership Clustering membership可以通过使用非常简单的multicast pings被建立。每个Tomcat实例定期会发出multicast ping,在ping message里,这个实例会散布它的IP 及 TCP 监听端口以用于复制。如果一个实例在所给的时间范围内还没有收到这样的ping,这个会员就被认为是不存在了。很简单,也很有效。当然,你需要在你的系统上让multicasting可被使用。
TCP Replication,在收到一个multicast ping以后,会员就被添加到群集里。在下一个复制请求时,发出请求的实例将使用host和port信息来建立一个TCP socket。通过使用这个socket,它把分段的数据发送过去。选择TCP sockets 的原因是它具备有流量控制,并确保发送到位。当发送数据时,这个数据就会被送到。
Distributed locking and pages using frames: Tomcat 并没有让会话实例在群集之间保持一致。这个逻辑的实现需要太大空间,也会带来很多问题。如果你的客户使用多个请求同时访问同一个会话,那么最后一个请求会覆盖群集里的其它会话。