目前,為了使web能適應大規模的訪問,需要實現應用的叢集部署。叢集最有效方案就是負載平衡,而實現負載平衡使用者沒一個請求都有可能被分配到不固定的伺服器上,這樣我們首先要解決session的統一來保證無論使用者的請求被轉寄到哪個伺服器上都能保證使用者的正常使用,即需要實現session的共用機制。
在叢集系統下實現session統一的有如下幾種方案:
(1) 應用伺服器間的session複製共用(如tomcat內建session共用)
(2) 基於cache DB緩衝的session共用
應用伺服器間的session複製共用(Tomcat內建的功能)
session複製共用,主要是指叢集環境下,多台應用伺服器之間同步session,使session保持一致,對外透明。 如果其中一台伺服器發生故障,根據負載平衡的原理,web伺服器(apache/nginx)會遍曆尋找可用節點,分發請求,由於session已同步,故能保證使用者的session資訊不會丟失。
此方案的不足之處: 技術複雜,必須在同一種中介軟體之間完成(如:tomcat-tomcat之間). session複製帶來的效能損失會快速增加.特別是當session中儲存了較大的對象,而且對象變化較快時, 效能下降更加顯著. 這種特性使得web應用的水平擴充受到了限制。 Session內容序列化(serialize),會消耗系統效能。 Session內容通過廣播同步給成員,會造成網路流量瓶頸,即便是內網瓶頸。
基於 Memcached 緩衝的 session 共用
即使用cacheDB存取session資訊,應用伺服器接受新請求將session資訊儲存在cache DB中,當應用伺服器發生故障時,web伺服器(apache/nginx)會遍曆尋找可用節點,分發請求,當應用伺服器發現session不在本機記憶體時,則去cache DB中尋找,如果找到則複製到本機,這樣實現session共用和高可用。
目前有開源的msm用於解決tomcat之間的session共用:Memcached_Session_Manager(MSM)
http://code.google.com/p/memcached-session-manager/
一個高可用的Tomcat session共用解決方案,除了可以從本機記憶體快速讀取Session資訊(僅針對黏性Session)外,同時可使用memcached存取Session,以實現高可用。 特性 支援Tomcat6、Tomcat7支援黏性、非黏性Session 無單一故障點 可處理tomcat容錯移轉 可處理memcached容錯移轉 外掛程式式session序列化 允許非同步儲存session,以提升響應速度 只有當session有修改時,才會將session寫回memcached JMX管理&監控
該方案的不足之處: memcache支援的資料結構比較單一 memcache的記憶體必須足夠大,否則會出現使用者session從Cache中被清除 需要週期性重新整理緩衝 伺服器故障時,存在於記憶體的memcache資料將會丟失
為瞭解決基於memcache中存在的不足,故提出了下面的一種解決方案:
基於redis緩衝的session共用
結合上面的分析後,由 redis 負責 session 資料的儲存,而我們自己實現的 session manager 將負責 session 生命週期的管理。利用 redis 自身的key到期時間機智,我們不再需要定期重新整理和做其他額外的處理。
截止到2015-09-20 前是不支援Tomcat8的,開源git 地址:https://github.com/jcoleman/tomcat-redis-session-manager
因為我們使用redis 來儲存Session,所以前提是redis已經安裝和配置完成。(本文不進行redis 的安裝配置說明)
使用步驟:
1、將 tomcat-redis-session-manager-1.2.jar 、jedis-2.6.1.jar、commons-pool2-2.2.jar 三個jar包拷貝到tomcat7/lib中。
2、在Tomcat 的conf/context.xml 檔案裡增加如下內容(或者在server.xml的context塊中添加): [html] view plain copy <Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" /> <Manager className="com.radiadesign.catalina.session.RedisSessionManager" host="localhost" <!-- 可選,預設是"localhost" --> port="6379" <!-- 可選,預設是 "6379" --> database="0" <!-- 可選,預設是 "0" --> maxInactiveInterval="60" <!-- 可選,預設是 "60" (單位:秒)--> /> 3、重啟Tomcat7,到redis 中查看session_id,如下: [html] view plain copy 127.0.0.1:6379> keys WJ* 1) "WJSESSIONID:6D5B0E0FD89E3A170B8BC5B8C112D3FD" 2) "WJSESSIONID:9546B26D78C99E8F0BF785535E319271" 3) "WJSESSIONID:839A35CFE17E900A81F50D629C104D2F" 4) "WJSESSIONID:1C287C797CF00C82BBBF37A617A3B55C" 5) "WJSESSIONID:FA2822C5021139641760754242F73393" 6) "WJSESSIONID:E904369E5B24D39B4E25515D50650EA6" 127.0.0.1:6379>
這裡進行一下特殊說明:
git 開源項目是直接將SESSIONID作為key儲存到redis中的,如下所示: [html] view plain copy 1) "6D5B0E0FD89E3A170B8BC5B8C112D3FD" 2) "9546B26D78C99E8F0BF785535E319271" 3) "839A35CFE17E900A81F50D629C104D2F" 4) "1C287C797CF00C82BBBF37A617A3B55C" 5) "FA2822C5021139641760754242F73393" 6) "E904369E5B24D39B4E25515D50650EA6"
我對該項目做了一點修改。
修改原因包括幾點:
1、項目也有使用redis 做其他資料存放區,直接使用這樣的key儲存到redis中,直觀上無法區分哪些key是用來做session共用用的。
2、項目包括好幾個服務(web、wap、cms),每個服務都需要做負載平衡session共用,這樣以來無法區分哪些session是屬於哪個服務的。
3、很難統計每個服務的線上使用者數。
我在叢集部署中我的每個服務都有不同的sessionCookieName(web = WJSESSIONID、wap = MJSESSIONID、cms = CMSJSESSIONID)
不知道怎麼配置的,這裡簡單說一下,直接在tomcat7/conf/server.xml 的最下面的Context中增加 sessionCookieName 配置即可: [html] view plain copy <Context docBase="F:\workspace\web" path="" reloadable="false" sessionCookieName="WJSESSIONID" />
我修改後的項目已經共用到:http://download.csdn.net/detail/catoop/9122857 (項目是一個maven項目)
其中 tomcat-redis-session-manager\target\tomcat-redis-session-manager-1.2.jar 可以直接使用。