1. 程式人生 > 實用技巧 >分散式 WEB應用中Session(會話管理)的變遷之路

分散式 WEB應用中Session(會話管理)的變遷之路

一、Session 介紹


Session 一詞直譯為 “會話”,意指有始有終的一系列動作/訊息。Session 是 Web 應用蓬勃發展的產物之一。在 Web 應用中隱含有“面向連線”和“狀態保持”兩個含義,同時也指代了 Web 伺服器與客戶端之間進行狀態保持的解決方案。

在 Web 應用誕生之初,應用伺服器與瀏覽器之間僅僅只是基於 HTTP 協議進行通訊。而 HTTP 協議是無狀態的,也就是說每一個請求之間都是相互獨立的,互不關聯。但是隨著應用業務的複雜,伺服器需要按照使用者的一系列業務操作向用戶提供某些特定的、按需的內容。這時候就需要通過儲存使用者狀態,將使用者的請求關聯起來。Session 管理正是這一問題的解決方案。

二、單體架構


早期的 Web 應用基本都採用的是單體架構,也就是把一個使用了分層架構的 Web 應用部署在單節點 Web 伺服器上。雖然採用了分層架構,將整個應用分為了表現層、業務邏輯層和資料訪問層,每一層各司其職,讓 Web 應用的各個方面都有所改善。但這樣的分層只停留於邏輯層面。由於將所有應用都部署在單個伺服器節點上,隨著應用的不斷迭代開發,單體應用將會發展成巨石應用,臃腫不堪,難以維護。

在這樣的單體架構中,由於所有的使用者請求都是由這個唯一的伺服器進行響應處理,所以只需要把儲存了使用者資訊和狀態的 Session 物件,存放在應用伺服器的記憶體中,就能輕鬆地達到保持使用者狀態的目的。

三、叢集和分散式架構


隨著 Web 應用的發展,使用者訪問量和業務複雜度與日俱進,應用的效能和程式碼的維護難度成為應用的瓶頸,為了突破瓶頸,開發者開始嘗試在應用架構中引入負載均衡器,繼而演化出了叢集分散式兩種架構型別。

叢集:是指在多個伺服器節點上部署相同的應用,例如上圖中的伺服器B和伺服器C,然後通過負載均衡的分發功能,把使用者請求分發到叢集中的任意一個服務節點上。如果有更大的訪問量,只要向叢集中增加伺服器節點,就能改善壓力。叢集既能保證應用的高可用,又能提高應用的負載能力。

分散式:是把原來的單體架構應用,通過分而治之的手段,按照業務功能,切分成一些小的模組應用,部署在不同伺服器節點上,例如上圖中的伺服器A和伺服器B。然後通過負載均衡和門戶應用整合起來,組成一個完成的應用。

叢集和分散式架構中,後端包含了多個伺服器節點。當用戶進行登入時,登入請求是由其中一個伺服器節點進行響應,而後續的使用者請求將可能被負載均衡器分發到其他伺服器節點,這時候就可能因為這個服務節點上沒有使用者 Session ,導致伺服器判定使用者是未登陸狀態,讓使用者重新登入。所以,在叢集和分散式架構中,必須保證使用者進行登入後,架構中的所有伺服器節點都能共享 Session 資料,常用的 Session 管理方案有如下3種:

方案一:將 Session 物件儲存在 Cookie,然後存放在瀏覽器端


每次瀏覽器向伺服器傳送請求的時候,都會把整個 Session 物件放在請求裡一起傳送到伺服器,以此來實現 Session 共享。這種方法實現起來特別方便,但是由於 Cookie 的儲存容量較小,且不安全。所以這個方案只適用於 Session 數量小和安全性不高的場景。

方案二:Session 複製


部分應用伺服器能夠支援 Session 複製功能,例如 Tomcat。使用者可以通過修改配置檔案,讓應用伺服器進行 Session 複製,保持每一服務節點的 Session 資料達成一致。但是這個方案的實現依賴於應用伺服器。當應用被大量使用者訪問時,每個伺服器都需要有一部分記憶體用來存放 Session,同時因為大量 Session 通過網路傳輸進行復制,將會佔用網路資源,這可能因為網路延遲導致程式異常。

方案三:Session 粘滯


利用負載均衡的分發能力,將同一瀏覽器上同一使用者的請求,都定向傳送都固定的伺服器上,讓這個伺服器處理該使用者的所有請求,這樣只要這個伺服器上儲存的使用者 Session,就能保證使用者的狀態一致性。但是這個方案依賴於負載均衡器,而且只適用於橫向擴充套件的叢集場景,不能滿足分散式場景。同時,當指定的伺服器宕機後,會session 資訊丟失的情況。也無法利用 Nginx負載均衡,提高伺服器的利用率,而且如果 Nginx不是放在最前面一層,那麼拿到的就可能不是使用者的真實ip,那麼轉發到的伺服器就會不一樣。

1 upstream backend{
2     server 127.0.0.1:8001;
3     server 127.0.0.1:8002;
4     ip_hash;
5 }

方案四:Session 集中管理方案選擇


這裡簡單介紹下 Spring Session。Spring Session 是 Spring 提供的一套 Session 管理方案,通過一個 SessionFilter 將所有訪問應用的請求都攔截下來,然後使用 Request 包裝類接管 Session 管理。將 Session 從Web 容器中攔截下來後,Session 會被儲存在獨立的儲存伺服器中。目前支援多種形式的 Session 儲存器:Redis、Database、MogonDB等。當 Request 進入 Web 容器,根據 Request 獲取 Session 時,由 Spring Session 負責從儲存器中獲取 Session,如果存在則返回,如果不存在則建立並持久化至儲存器中。Spring Session不與應用伺服器耦合,能使用於常規伺服器。同時還提供了瀏覽器下對同一應用儲存多個 Session 等功能。

【1】引入Spring-Session 相關 jar 包:

1 <!-- redis -->
2 <dependency>
3     <groupId>org.springframework.session</groupId>
4     <artifactId>spring-session-data-redis</artifactId>
5     <version>1.3.1.RELEASE</version>
6     <type>pom</type>
7 </dependency>

【2】 在 web.xml中,加入關於session的過濾器,只有這樣session才會被 Redis所操縱:就實現了 Redis對 session的管理。

1 <filter>
2     <filter-name>springSessionRepositoryFilter</filter-name>
3     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
4 </filter>
5 <filter-mapping>
6     <filter-name>springSessionRepositoryFilter</filter-name>
7     <url-pattern>/*</url-pattern>
8 </filter-mapping>