nginx集群tomcat,session共享問題


場景:

通過負載均衡之后,用戶第一次請求的tomcat和第二次請求的tomcat基本不是同一個,但是你在第一次請求放在session中的值只有一個tomcat才, 第二個請求的那個tomcat里面是沒有的。這樣就出現了用戶不停登入的情況。

方法一:復制session信息

原理:講道理,這個方法比較蠢,就是有幾個tomcat,就復制幾個session,只要有一個tomcat中的session發生變化,其他tomcat中的session跟着復制變化, 保證所有用戶的session在所有的tomcat中都存在而且相同。這樣一來無論用戶的請求被分配到哪個tomcat都是無所謂的,因為所有的tomcat中都有他們存放的session。

打個比方:如果tomcat相當於飯店,會話相當於筷子的話,如果每次吃飯都要用自己的筷子,那是不是要把每個飯店都放一雙自己的筷子。這就是這個方法的原理。

實現:

1、修改sever.xml文件:將Cluster的注釋去掉

2、打開自己項目的web.xml(不是tomcat/conf/web.xml),增加distributable。


優點:實現簡單,沒有什么花里胡哨的操作。如果集群的tomcat不多,而且用戶沒有那么多的時候可以選擇這種方式。

缺點:只要Session數據有變化,就需要將數據同步到所有其他機器上,機器越多,同步帶來的網絡帶寬開銷就越大;當用戶很多時,
每台機器用於保存Session數據的內容占用會很嚴重。


方法二:ip綁定

原理:說白了就是上篇中說到的負載均衡算法的ip綁定,就是你第一次訪問哪個tomcat,之后所有的請求都會被分配到那個tomcat上。

打個比方:如果tomcat相當於飯店,會話相當於筷子的話,要保證每次吃飯都用自己的筷子的話,我就把筷子存在某一家飯店,並且每次都去這家店吃飯。

優點:實現也比較簡單,需要修改一下nginx的配置文件即可。

缺點:

1、一大堆人連同一個網訪問的時候,就沒有負載均衡這一說了,這一大堆的ip都是一樣,都去訪問同一個tomcat。

2、如果這個人訪問的tomcat突然掛了,那nginx的故障轉移機制將會分發給另一個tomcat服務器,這樣一來所有請求這個tomcat的所有用戶就又需要重新登入了。

3、如果這個人用着用着突然在用的網絡不穩定,然后這個人換了另一個網,這樣ip一換,這個人又要重新登入了。


方法三:tomcat-redis-session-manager(開源項目--基於redis實現)

session管理:
1.Manager接口類
定義了用來管理session的基本接口,包括:createSession,findSession,add,remove等對session操作的方法;
還有getMaxActive,setMaxActive,getActiveSessions活躍會話的管理;還有Session有效期的接口;以及與Container相關聯的接口;

2.ManagerBase抽象類
實現了Manager接口,提供了基本的功能,使用ConcurrentHashMap存放session,提供了對session的create,find,add,remove功能,
並且在createSession中了使用類SessionIdGenerator來生成會話id,作為session的唯一標識;

3.ClusterManager接口類
實現了Manager接口,集群session的管理器,Tomcat內置的集群服務器之間的session復制功能;

4.ClusterManagerBase抽象類
繼承了ManagerBase抽象類,實現ClusterManager接口類,實現session復制基本功能;

5.PersistentManagerBase抽象類
繼承了ManagerBase抽象類,實現了session管理器持久化的基本功能;內部有一個Store存儲類,具體實現有:FileStore和JDBCStore;

6.StandardManager類
繼承ManagerBase抽象類,Tomcat默認的Session管理器(單機版);對session提供了持久化功能,tomcat關閉的時候會將session保存到javax.servlet.context.tempdir路徑下的SESSIONS.ser文件中,
啟動的時候會從此文件中加載session;

7.PersistentManager類
繼承PersistentManagerBase抽象類,如果session空閑時間過長,將空閑session轉換為存儲,所以在findsession時會首先從內存中獲取session,
獲取不到會多一步到store中獲取,這也是PersistentManager類和StandardManager類的區別;

8.DeltaManager類
繼承ClusterManagerBase,每一個節點session發生變更(增刪改),都會通知其他所有節點,其他所有節點進行更新操作,任何一個session在每個節點都有備份;

9.BackupManager類
繼承ClusterManagerBase,會話數據只有一個備份節點,這個備份節點的位置集群中所有節點都可見;相比較DeltaManager數據傳輸量較小,
當集群規模比較大時DeltaManager的數據傳輸量會非常大;

10.RedisSessionManager類
繼承ManagerBase抽象類,非Tomcat內置的管理器,使用redis集中存儲session,省去了節點之間的session復制,依賴redis的可靠性,比起sessin復制擴展性更好;

Tomcat提供了一個開放的session管理和持久化的org.apache.catalina.session.ManagerBase,繼承這個抽象類並做一些簡單的配置,
即可讓你的session管理類接管Tomcat的session讀取和持久化,這里使用的是tomcat-redis-session-manager來管理session;
RedisSessionManager繼承於org.apache.catalina.session.ManagerBase類,對session的相關操作都在此類中;

修改$TOMCAT_HOME/conf目錄下的context.xml文件
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="localhost"
port="6379"
database="0"
maxInactiveInterval="60"/>


方法四:使用jwt(推薦使用)

原理:放棄session機制,使用jwt機制。簡單來說就是userid+隨機數+簽名加密生成一個token,前后端通信通過token來交互。客戶端第一次請求登入之后,
服務器端給客戶端一個token,服務器將token作為key值,userid作為value值,30分鍾作為有效時間存入redis中;客戶端第二次訪問controller之前進行攔截,
判斷是否有token,如果有token解密獲取userid,然后取查詢redis,token和userid是否匹配,如果匹配就允許訪問controller,請求返回之后,
服務器將重新生成新的token返回給客戶端。簡單來說就是每次請求成功之后token都會改變,token存在redis中,這樣一來至於redis分發到哪個tomat並不影響,
因為token是存在redis中的。

方法五:使用 spring session


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM