這是之前項(xiàng)目使用Keepalived時(shí)遇到如何保持會(huì)話的,通俗的講就是當(dāng)VIP發(fā)生切換的時(shí)候,如果保持會(huì)話的持續(xù)性,就是不會(huì)讓用戶發(fā)生重新登錄的問(wèn)題。這里主要講一講Tomcat中Session復(fù)制的問(wèn)題。
1.Tomcat會(huì)話保持的原理
由于HTTP是無(wú)狀態(tài)的協(xié)議,客戶程序每次都去web頁(yè)面,都打開到web服務(wù)器的單獨(dú)的連接,并且不維護(hù)客戶的上下文信息。比如用戶登錄系統(tǒng)后,每次都能夠知道操作的是此登錄用戶,而不是其他用戶。這篇文章非常好的解釋了這一原理:Tomcat官網(wǎng)
比如我們的項(xiàng)目架構(gòu)圖大概是這樣的:

我在項(xiàng)目中的配置如下:


利用上述配置我們可以把session利用DeltaManager來(lái)復(fù)制到其他的節(jié)點(diǎn)機(jī)器上,但是這個(gè)比較適合小的集群中使用,不推薦在大的集群中使用,當(dāng)我們使用DeltaManager復(fù)制到其他節(jié)點(diǎn)時(shí),我們其他節(jié)點(diǎn)的項(xiàng)目可以不需要重新部署。
2.SimpleTcpCluster核心類的解釋
稍微懂點(diǎn)英文的都能看懂的,不懂的直接Google翻譯。感覺(jué)英文解釋很好,就不用翻譯成中文了。
A Cluster implementation using simple multicast.(組播) Responsible for setting up a cluster and provides callers with a valid multicast receiver/sender.
組播傳輸:在發(fā)送者和每一接收者之間實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)連接,如果一臺(tái)發(fā)送者同時(shí)給多個(gè)接收者傳輸相同的數(shù)據(jù),也只需要復(fù)制一份的相同數(shù)據(jù)包,它提高了數(shù)據(jù)的傳輸效率。
在因特網(wǎng)中的IP組播也是用組播組的概念,每個(gè)組都有一個(gè)特別分配的地址,要給該組發(fā)送的計(jì)算機(jī)將使用這個(gè)地址作為分組的目標(biāo)地址。在IPv4中,這些地址在D類地址空間中分配,而IPv6也有一部分地址空間保留給組播組。
需要注意的是,主機(jī)組播時(shí)僅發(fā)送一份數(shù)據(jù),只有數(shù)據(jù)在傳送路徑出現(xiàn)分岔時(shí)才將分組復(fù)制后繼續(xù)轉(zhuǎn)發(fā)。主機(jī)使用一個(gè)稱作IGMP(因特網(wǎng)組管理協(xié)議)的協(xié)議加入組播組。組播一定是僅應(yīng)用于UDP。(比如應(yīng)用于視頻點(diǎn)播和視頻會(huì)議)

3.這是默認(rèn)的集群的配置文件(重要的幾個(gè)參數(shù))
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

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的標(biāo)簽注釋)
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 (負(fù)載均衡)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.(通過(guò)cookie來(lái)記錄session的狀態(tài))
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.實(shí)現(xiàn)Session復(fù)制的三種方法
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)(共享文件系統(tǒng))
2.Using session persistence, and saving the session to a shared database (PersistenceManager + JDBCStore)(共享數(shù)據(jù)庫(kù))
3.Using in-memory-replication, using the SimpleTcpCluster that ships with Tomcat (lib/catalina-tribes.jar + lib/catalina-ha.jar)(組播的方式)

6.Tomcat復(fù)制session的具體過(guò)程如下
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.
下面是對(duì)每個(gè)步驟的具體解釋:
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中發(fā)現(xiàn)distributable,Tomcat中的SimpleTcpCluster中創(chuàng)建一個(gè) 管理者管理這些要復(fù)制的上下文). 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) (組播服務(wù))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(重點(diǎn)). 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.結(jié)語(yǔ)
雖然這篇文章都是英文,但是我覺(jué)得比中文翻譯出來(lái)的要好很多,也希望大家多看英文,免得翻譯過(guò)來(lái)有歧義。(ps:其實(shí)我英文也不好......)