这是之前项目使用Keepalived
时遇到如何保持会话的,通俗的讲就是当VIP发生切换的时候,如果保持会话的持续性,就是不会让用户发生重新登录的问题。这里主要讲一讲Tomcat中Session复制的问题。
1.Tomcat会话保持的原理
由于HTTP是无状态的协议,客户程序每次都去web页面,都打开到web服务器的单独的连接,并且不维护客户的上下文信息。比如用户登录系统后,每次都能够知道操作的是此登录用户,而不是其他用户。这篇文章非常好的解释了这一原理:Tomcat官网
比如我们的项目架构图大概是这样的:
image.png我在项目中的配置如下:
image.png image.png利用上述配置我们可以把session
利用DeltaManager
来复制到其他的节点机器上,但是这个比较适合小的集群中使用,不推荐在大的集群中使用,当我们使用DeltaManager
复制到其他节点时,我们其他节点的项目可以不需要重新部署。
2.SimpleTcpCluster核心类的解释
稍微懂点英文的都能看懂的,不懂的直接Google翻译。感觉英文解释很好,就不用翻译成中文了。
A Cluster implementation using simple multicast.(组播) Responsible for setting up a cluster and provides callers with a valid multicast receiver/sender.
组播传输:在发送者和每一接收者之间实现点对点网络连接,如果一台发送者同时给多个接收者传输相同的数据,也只需要复制一份的相同数据包,它提高了数据的传输效率。
在因特网中的IP组播也是用组播组的概念,每个组都有一个特别分配的地址,要给该组发送的计算机将使用这个地址作为分组的目标地址。在IPv4中,这些地址在D类地址空间中分配,而IPv6也有一部分地址空间保留给组播组。
1.jpg需要注意的是,主机组播时仅发送一份数据,只有数据在传送路径出现分岔时才将分组复制后继续转发。主机使用一个称作IGMP(因特网组管理协议)的协议加入组播组。组播一定是仅应用于UDP。(比如应用于视频点播和视频会议)
3.这是默认的集群的配置文件(重要的几个参数)
Here are some of the important default values:
1.Multicast address is 228.0.0.4
2.Multicast port is 45564 (the port and the address together determine cluster membership.
3.The IP broadcasted is java.net.InetAddress.getLocalHost().getHostAddress() (make sure you don't broadcast 127.0.0.1, this is a common error)
4.The TCP port listening for replication messages is the first available server socket in range 4000-4100
5.Listener is configured ClusterSessionListener
6.Two interceptors are configured TcpFailureDetector and MessageDispatchInterceptor
image.png
4.集群中的基本配置
To run session replication in your Tomcat 8 container, the following steps should be completed:
1.All your session attributes must implement java.io.Serializable(序列化)
2.Uncomment the Cluster element in server.xml(取消server.xml中Cluster的标签注释)
3.If you have defined custom cluster valves, make sure you have the ReplicationValve defined as well under the Cluster element in server.xml
4.If your Tomcat instances are running on the same machine, make sure the Receiver.port attribute is unique for each instance, in most cases Tomcat is smart enough to resolve this on it's own by autodetecting available ports in the range 4000-4100
5.Make sure your web.xml has the <distributable/> element(确保web.xml中添加了<distributable>)
If you are using mod_jk, make sure that jvmRoute attribute is set at your Engine <Engine name="Catalina" jvmRoute="node01" > and that the jvmRoute attribute value matches your worker name in workers.properties
6.Make sure that all nodes have the same time and sync with NTP service!
7.Make sure that your loadbalancer (负载均衡)is configured for sticky session mode.
8.Load balancing can be achieved through many techniques, as seen in the Load Balancing chapter.
Note(注意):
Remember that your session state is tracked by a cookie, so your URL must look the same from the out side otherwise, a new session will be created.(通过cookie来记录session的状态)
The Cluster module uses the Tomcat JULI logging framework, so you can configure logging through the regular logging.properties file. To track messages, you can enable logging on the key: org.apache.catalina.tribes.MESSAGES(日志追踪)
5.实现Session复制的三种方法
To enable session replication in Tomcat, three different paths can be followed to achieve the exact same thing:
1.Using session persistence, and saving the session to a shared file system (PersistenceManager + FileStore)(共享文件系统)
2.Using session persistence, and saving the session to a shared database (PersistenceManager + JDBCStore)(共享数据库)
3.Using in-memory-replication, using the SimpleTcpCluster that ships with Tomcat (lib/catalina-tribes.jar + lib/catalina-ha.jar)(组播的方式)
image.png
6.Tomcat复制session的具体过程如下
To make it easy to understand how clustering works, We are gonna take you through a series of scenarios. In the scenario we only plan to use two tomcat instances TomcatA and TomcatB. We will cover the following sequence of events:
1.TomcatA starts up
2.TomcatB starts up (Wait that TomcatA start is complete)
3.TomcatA receives a request, a session S1 is created.
4.TomcatA crashes
5.TomcatB receives a request for session S1
6.TomcatA starts up
7.TomcatA receives a request, invalidate is called on the session (S1)
8.TomcatB receives a request, for a new session (S2)
9.TomcatA The session S2 expires due to inactivity.
下面是对每个步骤的具体解释:
Ok, now that we have a good sequence, we will take you through exactly what happens in the session replication code
1.TomcatA starts up
Tomcat starts up using the standard start up sequence. When the Host object is created, a cluster object is associated with it. When the contexts are parsed, if the distributable element is in place in web.xml Tomcat asks the Cluster class (in this case SimpleTcpCluster) to create a manager for the replicated context(如果在web.xml中发现distributable,Tomcat中的SimpleTcpCluster中创建一个 管理者管理这些要复制的上下文). So with clustering enabled, distributable set in web.xml Tomcat will create a DeltaManager for that context instead of a StandardManager. The cluster class will start up a membership service (multicast) (组播服务)and a replication service (tcp unicast)(TCP单播). More on the architecture further down in this document.
2.TomcatB starts up
When TomcatB starts up, it follows the same sequence as TomcatA did with one exception. The cluster is started and will establish a membership (TomcatA,TomcatB). TomcatB will now request the session state from a server that already exists in the cluster, in this case TomcatA. TomcatA responds to the request, and before TomcatB starts listening for HTTP requests, the state has been transferred from TomcatA to TomcatB. In case TomcatA doesn't respond, TomcatB will time out after 60 seconds, and issue a log entry. The session state gets transferred for each web application that has distributable in its web.xml(重点). Note: To use session replication efficiently, all your tomcat instances should be configured the same.
3.TomcatA receives a request, a session S1 is created
The request coming in to TomcatA is treated exactly the same way as without session replication. The action happens when the request is completed, the ReplicationValve will intercept the request before the response is returned to the user. At this point it finds that the session has been modified, and it uses TCP to replicate the session to TomcatB. Once the serialized data has been handed off to the operating systems TCP logic, the request returns to the user, back through the valve pipeline. For each request the entire session is replicated, this allows code that modifies attributes in the session without calling setAttribute or removeAttribute to be replicated. a useDirtyFlag configuration parameter can be used to optimize the number of times a session is replicated.
4.TomcatA crashes
When TomcatA crashes, TomcatB receives a notification that TomcatA has dropped out of the cluster. TomcatB removes TomcatA from its membership list, and TomcatA will no longer be notified of any changes that occurs in TomcatB. The load balancer will redirect the requests from TomcatA to TomcatB and all the sessions are current.
5.TomcatB receives a request for session S1
Nothing exciting, TomcatB will process the request as any other request.
6.TomcatA starts up
Upon start up, before TomcatA starts taking new request and making itself available to it will follow the start up sequence described above 1) 2). It will join the cluster, contact TomcatB for the current state of all the sessions. And once it receives the session state, it finishes loading and opens its HTTP/mod_jk ports. So no requests will make it to TomcatA until it has received the session state from TomcatB.
7.TomcatA receives a request, invalidate is called on the session (S1)
The invalidate call is intercepted, and the session is queued with invalidated sessions. When the request is complete, instead of sending out the session that has changed, it sends out an "expire" message to TomcatB and TomcatB will invalidate the session as well.
8.TomcatB receives a request, for a new session (S2)
Same scenario as in step 3)
9.TomcatA The session S2 expires due to inactivity.
The invalidate call is intercepted the same was as when a session is invalidated by the user, and the session is queued with invalidated sessions. At this point, the invalidated session will not be replicated across until another request comes through the system and checks the invalid queue.
7.结语
虽然这篇文章都是英文,但是我觉得比中文翻译出来的要好很多,也希望大家多看英文,免得翻译过来有歧义。(ps:其实我英文也不好......)
网友评论