在第三,四篇文章中講到了會話保持的問題,並且還遺留了一個問題,就是會話保持存在單點故障,html
當時的方案是cookie插入後綴,即haproxy指負責分發請求,應用服務自行保持用戶會話,若是應git
用服務器宕機,則session會丟失。github
如今來溫習下解決方案web
方案1:session複製redis
原理apache |
就是將1臺服務器的session複製到其它全部的服務器上,這樣不管訪問哪臺服務器,都會獲得用戶 的session瀏覽器 |
優勢緩存 |
不存在單點故障問題tomcat |
缺點安全 |
當服務器的數量比較大時,session同步將會變得至關耗時 |
方案2:session粘滯
原理 |
就是用戶請求一個服務器以後,同一個會話的其它請求,都會被分配到這臺服務器,session粘滯的 功能由負載均衡中間件完成 |
優勢 |
解決了session複製的性能問題 |
缺點 |
因爲用戶的會話被保存到單一的服務器,就容易出現單點故障 |
方案3:session服務器
原理 |
部署一個專門的服務,保存用戶session,同時在web服務器本地也保存一份,當本地沒有或者失效時, 去訪問session服務器,固然session服務器就成了單點,當用戶量大的時候也容易宕機,這時能夠作一 個session服務器集羣,作主備同步備份,這樣就達到了較好的效果,具體實現能夠用redies,memcached 等緩存中間件。 |
優勢 |
解決了單點故障和性能問題 |
缺點 |
實現複雜 |
redis保存session方案
上篇文章講到的就是session粘滯的方案,既然前2種方案都有各自的缺點,那麼就採用第三中方案
能夠用redis作session緩存,保存用戶session,作成主備模式,採用同步備份或者異步備份。
同步備份:在主機宕機時,備機接管以後session數據不丟失。
異步備份:在主機宕機時,備機接管主機,可是若是有一部分session還沒來得及同步到備機,session將丟失。
能夠根據實際狀況來決定採用同步備份仍是異步備份。
系統架構圖以下:
若是用戶量比較大,單服務器訪問和存儲session將會成爲瓶頸,能夠考慮用session服務器集羣,架構圖以下:
redis集羣特色
1)將數據分散到集羣中的多個節點,每一個節點存儲的數據量就會變少,這樣存儲和訪問
的效率會獲得提高。
2)每一個節點都有主備,若是節點的主存儲掛了,備份存儲會接管主存儲,提升可用性。
session流程
1.客戶端首次請求服務端
2.服務端產生session並set cookie響應給客戶端
3.客戶端再次請求服務端,會帶上cookie
4.服務端根據cookie找到對應的session
實現思路
若是咱們要編寫程序實現這個方案,須要解決如下問題:
1.session的安全性,即不容易被仿造。
2.session的惟一性,若是用tomcat產生session的策略,多臺tomcat會產生的session會存在重複的可能。
3.session的有效期維護,session會有個有效期,用戶在這個時間內不訪問系統,session將會失效,若是
用戶一直訪問,則要自動延長session有效期。
4.在集羣session服務器中,要考慮負載均衡,這也是須要編寫客戶端代碼的,在分佈式session緩存中,
須要根據sessionId哈希分佈,那麼就和服務器個數進行了耦合,在添加和移除服務器的時候,將出現數
據不一致的問題 。
5.如何實現才能讓應用程序改動最小,或者是不改動。
咱們能夠選擇本身寫程序來實現以上功能,不過在這裏我使用一個現成的框架,即tomcat-redis-session-manager
有時間並感興趣的朋友,能夠在這個基礎上自行實現一個,這樣更適合本身的項目。
服務器部署分佈:
ha主機 192.168.1.227:80
ha備機 192.168.1.246:80
keepalived 主機 192.168.1.227
keepalived備機 192.168.1.246
web1 http://192.168.1.226:8888/login
web2 http://192.168.1.246:8888/login
redis主 192.168.1.245 6380
redis備
安裝redis
主機和備機都安裝redis
wget http://download.redis.io/releases/redis-2.8.5.tar.gz
解壓:
tar xzf redis-2.8.5.tar.gz
cd redis-2.8.5
make
啓動
src/redis-server redis.conf --port 6380 &
客戶端登陸
src/redis-cli -p 6380
備機配置複製:
redis.conf文件中
添加
slaveof 192.168.1.245 6380
Tomcat配置
tomcat版本:7.0.61
相關jar包:
注意這裏的jar包最好是按下面的版本,不然會出現jar包衝突的問題。
tomcat-redis-session-manager-1.1.jar
commons-pool-1.6.jar
jedis-2.1.0.jar
下載tomcat redis session manager
https://github.com/jcoleman/tomcat-redis-session-manager/downloads
下載 apache common pool
http://commons.apache.org/proper/commons-pool/download_pool.cgi
下載版本:tomcat-redis-session-manager-1.1
redis的jar包能夠從maven中央倉庫下載
將以上3個jar包放入tomcat/lib目錄中
在tomcat context.xml中加入以下內容
<!-- host: optional: defaults to "localhost" --> <!-- port: defaults to "6379" --> <!-- database: optional: defaults to "0" --> <!-- maxInactiveInterval: optional: defaults to "60" (in seconds) --> <Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" /> <Manager className="com.radiadesign.catalina.session.RedisSessionManager" host="192.168.1.245" port="6380" database="0" maxInactiveInterval="60" />
啓動tomcat,瀏覽器請求tomcat
http://192.168.1.226:8888/login/
登陸redis客戶端,查看session
session已經被保存到redis
下面,咱們進行一項測試
測試流程:
1.先訪問虛擬ip1.99的應用,獲得sessionId
web服務器是226
2.而後將對應的tomcat停掉
3.刷新該應用,若sessionId未變,則表示redis保存session成功。
咱們發現web服務器變成了246,可是sessionId未發生變化
該方案將session集中保存在了redis服務器,並作了主備容災,從必定程度上提升了系統的高可用,因爲
redis是內存存儲,訪問效率較高,在性能上也是比較好的,可是本例中session不是分佈式存儲,所以當用戶量
很是大,併發訪問量很是高的時候,session服務器會成爲性能瓶頸。