最近在讀一原本自淘寶技術團隊大牛的書,名字叫《大型網站系統與Java中間件實踐》。開篇的章節詳細地介紹了一個網站架構由小變大不斷演進的過程,其中從單機架構升級到集羣架構的過程當中着重介紹了關於session同步問題, 這也是不少人在聊到分佈式時繞不過去的話題。下面就整理下書中的內容,也算是作個讀書筆記,方便之後參考。web
作web開發的同窗應該對session再熟悉不過,它是服務器分配給客戶端的會話標識,瀏覽器每次請求會帶上這個標識來告訴服務器我是誰,服務器會在內存中存儲這些不一樣的會話信息,由此來分辨請求來自哪一個會話。在單機部署的環境總,由於web服務器和session都是在同一臺機器上,因此必然能找到對應的會話數據。但若是有2臺web服務器(A和B)提供服務,假如第一次請求落到A上並建立了session,那麼如何保證下次落到B的請求能讀到session數據? 數據庫
有如下4中常見的解決方案。 瀏覽器
一、Session Sticky 緩存
這是最簡單粗暴的 方法,核心思路就是讓同一會話的請求都落地到同一臺服務器上,這樣處理起來就和單機同樣了,咱們能夠在負載均衡上作一些身份識別並控制轉發來達到這個目的。這樣作的優點是能像單機同樣簡化對session處理,也方便作本地緩存,但缺點也是很明顯的: 安全
若是這臺服務器宕機或重啓了,那麼因此的會話數據都會丟失,失去了分佈式集羣帶來的高可用特性。 服務器
增長了負載均衡器的負擔,使它變得有狀態了,並且資源消耗會更大,容易成爲性能瓶頸。 cookie
二、Session Replication 網絡
顧名思義,這是一種session複製的方案,核心思路就是經過在服務器之間增長session同步機制來保證數據一致。session
看起來比第一種簡單了不少,也沒有第一種帶來的缺陷,但在某些應用場景下仍是會有比較嚴重的問題: 架構
服務器之間的數據同步帶來了額外的網絡消耗,隨着機器數量和數據量的上升,網絡帶寬將會有很大的壓力,也必然會帶來延時問題。
每臺服務器上都要存儲全部的會話數據,若是會話數量很大會佔用服務器大部份內存空間。
目前不少應用容器都支持這種同步方式,因此在集羣規模和數據量比較小的時候仍是一種很好的解決方案。
三、Session集中存儲
這種方式的思路就是把全部的會話數據統一存儲和管理,全部應用服務器須要對session進行讀寫都要經過session服務器來操做:
這種方案的好處是獨立了session的管理,職責單一化,session服務器採用什麼方式存儲(內存、數據庫、文檔、NoSql等等),什麼方式對外提供服務都是透明的。不會給應用系統和負載均衡帶來額外的開銷,不須要進行數據同步就能保證一致性,看起來應該是很是完美了,不過也有本身的一些小缺陷:
對session讀寫須要網絡操做,相比較session直接存儲在web服務器的時候增長了時延和不穩定性,好在session服務器和web服務器通常是部署在局域網中,能夠最大化減小這個問題。
session服務器出現問題將影響全部web服務,若是採用多機部署同時也會帶來數據一致性問題。
每種方案帶有它獨特的優點,同時也會帶來相應的新問題,正所謂沒有十全十美,只有適合纔是最好的。整體來講,這種方案在應用服務器和會話數據量都很大的時候仍是很是有優點的。
四、Cookie Base
這種方案是基於cookie的傳輸來實現的,核心思想很簡單,就是把完整的會話數據通過處理後寫入到客戶端cookie,之後客戶端每次請求都帶上這個cookie,而後服務端經過解析cookie數據來獲取會話信息,以下圖所示:
這種方案簡單明瞭,也沒有前面幾種方案帶來的問題,但劣勢也很是明顯:
首先經過cookie來傳遞關鍵數據確定是不安全的,即使是採用了特殊的加密手段。
若是客戶端禁用了cookie,將直接致使服務不可用。
cookie的數據是有大小限制的,若是傳遞的數據超出限制大小,將會致使數據異常。
在http請求中攜帶大量的數據進行傳輸會增長網絡負擔,一樣,服務端響應大量數據會致使請求變慢,併發量大的時候會很是可怕。
以上4種方案都是可行的方案,正如前面所說,每種方案各有優劣,不會十全十美,實際應用中要根據需求作權衡和取捨。這些都是屬於比較通用的方案,我相信在真正的實踐和落地過程當中還會有其餘問題出現,有經驗的過來人或許會有一些另闢蹊徑的「套路」,歡迎討論交流。