為了便于理解集群的工作機制,下面將通過一些實際情境來加深一下你的理解,我們只打算采用 2 個 Tomcat 實例:Tomcat A 和 Tomcat B。具體發生的事件流程為:
介紹完了事件序列,下面詳細剖析一下在會話復制代碼中到底發生了什么。
Tomcat A 啟動
Tomcat 使用標準啟動順序來啟動。Host 對象創建好之后,會關聯一個 Cluster 對象。在解析上下文時,如果 web.xml 中包含 distributable 元素,Tomcat 就會讓 Cluster 類(在該例中是 SimpleTcpCluster)創建復制的上下文的管理器。啟用了集群并在 web.xml 中設置了 distributable 元素后,Tomcat 會為該上下文創建一個 DeltaManager(而不是 StandardManager)。Cluster 類會啟動一個成員服務(組播)和一個復制服務(TCP 單播)。下文將會介紹更多的架構細節。
Tomcat B 啟動
Tomcat B 啟動時,采取的順序與 Tomcat A 基本一樣。集群啟動,建立成員(Tomcat A 與 Tomcat B)。Tomcat B 會請求集群中已有服務器(本例中是 Tomcat A)的會話狀態。如果 Tomcat A 響應該請求,那么在 Tomcat B 開始偵聽 HTTP 請求之前,Tomcat A 會將會話狀態傳到 Tomcat B那里;如果 Tomcat A 沒有響應該請求,Tomcat 會等待 60 秒,超過這個時間之后,發出一個日志項。該會話狀態會發送到每一個在 web.xml 中設置了 distributable 元素的應用。注意:為了有效地使用會話復制,所有的 Tomcat 實例都必須擁有相同的配置。
Tomcat A 接收一個請求,創建了一個會話 S1
Tomcat A 對發送給它的請求的處理方式,與沒有會話復制時的處理方式完全相同。請求完成時會觸發相應行為,ReplicationValve 會在響應返回用戶之前攔截請求。如發現會話已經更改,則使用 TCP 將會話復制到 Tomcat B 上。一旦序列化的數據被轉交給操作系統的 TCP 邏輯,請求就會重新通過 valve 管道返回給用戶。對于每一個請求,都將復制所有的會話,這樣做就有利于復制那些在會話中修改屬性的代碼,使其即使不必調用 setAttribute 或 removeAttribute,也能被復制。另外,使用 useDirtyFlag 配置參數也可以優化會話的復制次數。
Tomcat A 崩潰
當 Tomcat A 崩潰時,Tomcat B 會接到通知,得知 Tomcat A 已被移出集群,隨即 Tomcat B 就在其成員列表中也將 Tomcat A 移除,Tomcat B 從而不再收到關于 Tomcat A 的任何通知。負載均衡器會把從 Tomcat A 發送給 Tomcat B 的請求重新定向,所有的會話都將保持現有的狀態。
Tomcat B 接收到對會話 S1 的請求
毫無懸念,Tomcat B 會照處理其他請求的方式那樣來處理該請求。
Tomcat A 啟動
在 Tomcat A 開始接收新的請求之前,將會根據上面(1)(2)兩條所所說明的啟動序列來啟動。Tomcat A 會加入集群,聯系 Tomcat B 并獲取所有的會話狀態。一旦接收到會話狀態,就會完成加載,并打開 HTTP/mod_jk 端口。所以,除非 Tomcat A 從 Tomcat B 那里接收到了會話變更,否則沒有發給 Tomcat A 的請求。
Tomcat A 接收到一個請求,調用會話 S1 上的 invalidate 方法
會攔截對 invalidate 的調用, 并且 session 會被加入失效會話隊列。 在請求完成時,不會發送會話改變消息,而是發送一個 “到期” 消息給 Tomcat B,Tomcat B 也會讓此會話失效。
Tomcat B 接收到一個對新會話 S2 的請求
同步驟 3。
Tomcat A 會話 S2 由于不活躍而超時
invalidate 調用會被攔截,當一個會話被用戶標記失效時,該會話就會加入到無效會話隊列。此時,失效的會話不會被復制,直到另一個請求通過系統并檢查無效會話隊列。
Membership 集群成員是通過非常簡單的組播 ping 命令來實現的。每個 Tomcat 實例都會定期發送一個組播 ping,ping 消息中包含 Tomcat 實例自身的 IP 和配置的 TCP 監聽端口。如果實例在一個給定的時間內沒有收到這樣的 ping 信息,就會認為那個成員已經崩潰了。非常簡潔高效!當然,您需要在系統上啟用廣播。
TCP 復制 一旦收到一個多播 ping 包,在下一個復制請求時成員被添加到集群,發送實例將使用的主機和端口信息,以及建立TCP套接字。使用該套接字發送序列化的數據。之選擇TCP套接字,是因為它內建有流量控制和保證發送的功能。所以發送的數據肯定會到達那里。
分布式的鎖定與使用架構的頁面s Tomcat 在跨集群同步不保持會話實例。這種邏輯的實現將是多開銷和導致各種各樣的問題。如果你的客戶用同一個會話同時發送多個請求,那么最后的請求將會覆蓋集群中的其他會話。