Tomcat8+Redis叢集解決對談共用

2020-09-29 12:01:36

瞎  扯

磕磕碰碰一天,百度了好幾篇,終於搞定了Session共用的問題。以前只是聽說將Session存入第三方來解決Session共用問題,可一直沒有親自動手實現過,還記得以前面試時被一道怎麼用Redis解決Session共用問題給懟得老慘,現在再問到,雖然可能還是會被懟,但多多少少能說上幾句了。此文純粹是記錄我這一天解決這問題的過程,要想面試打敗面試官,多去找找其他博文。

問題起源:伺服器端Tomcat叢集,負載策略採用的Ip-Hash方式,不存在Session共用問題,後因Jmeter壓測,在無權更改測試機為多IP模擬IP欺騙的情況下,將負載策略更改為輪詢方式,然後,就有活幹了。 

參 考 致 謝

負載策略可參考:https://blog.csdn.net/qq_35119422/article/details/81505732

需要用到Redis Session Manager for Apache Tomcat專案,https://github.com/jcoleman/tomcat-redis-session-manager ,但是官方說的了,暫時不支援tomcat8,上Github上逛了一圈,無私奉獻的大神挺多的,因為我專案用到的是tomcat8.5,找了好幾個才找到個簡單可用的(沒有試是否支援其他版本)。

原始碼我用的這哥們的:https://github.com/cc-chen/tomcat8.5-redis-session-manager.git,萬分感謝!

下 載 配 置

省事的朋友們,可跳過原始碼,所需jar包我打好了,需要的自行下載:

下載地址:https://pan.baidu.com/s/1DuY-S9GHCgvWmTn1DvvvOg

提取碼:cg6g

解壓後為這三個jar包,

jedis-2.5.2.jar,

commons-pool2-2.2.jar

tomcat8.5-redis-session-manager.jar

將這三個包放在tomcat的lib目錄下,然後修改config目錄下context.xml檔案,新增如下設定(大多數博主通用設定):

<Valve className="com.s.tomcat.redissessions.RedisSessionHandlerValve" />

<Manager className="com.s.tomcat.redissessions.RedisSessionManager"

        host="127.0.0.1"

        port="6379"

        database="0"

        password="123456"     

        maxInactiveInterval="60" />

引數說明:

通用設定

className:tomcat8.5-redis-session-manager.jar中類全路徑,有木有發現,與網上其他大多數部落格寫的名稱不一樣,是因為該jar包有修改原官網專案包名。

host:redis master Ip地址

port:redis master 埠

password:redis密碼

database:資料庫下標(redis預設從0到15 16個分割區)

maxInactiveInterval:session超時時間,單位min(測試無效,該怎麼設定和失效原因後續會說明)

測試方法:

預設Redis主從叢集已經設定好,測試結果如下,(由於是本地,所以Tomcat,Redis均為偽叢集,也就是IP一樣埠不一樣)

在各個tomcat/webapp/ROOT 目錄下的jsp頁面合適位置加上IP:Port-Session Id : <%= request.getSession().getId() %>(我選擇的第51行),啟動tomcat8086,8087,tomcat啟動前保證Redis主從叢集執行正常,否則tomcat啟動會報錯,啟動成功後,存取tomcat主頁,在同一瀏覽器輸入:127.0.0.1:8086,127.0.0.1:8087,檢視頁面的sessionId以及reids中sessionId,如果如圖所示,恭喜你,成功一半了:

如果redis中存上了sessionId,且兩個tocat服務sessionId一樣,重複重新整理,sessionId不變,驗證成功。

然後刪除Redis中的sessionId,再次重新整理。

此時sessionId變了,但是兩個服務的sessionId仍然一樣,驗證成功。

大多數部落格到這就完了,但真的成功了麼?NO!

哨兵叢集設定

上面設定是大多數部落格都寫到的設定,不知道大家發現個問題沒,上面host設定只有一個地址,既主節點地址。當redis為單機時,或者叢集模式為主從模式時,這樣設定才好使,因為我們只需設定主節點連線資訊就可以了,但主節點宕了,不就崩了麼?現在大多數用到redis的服務,為保證其高可用,幾乎都會選擇哨兵模式或者Redis-Cluster模式吧。那麼問題來了,當主節點宕了後,當其他從節點升級為主節點後,節點連線資訊變了,那上面的設定是不是得改了?

不用驚訝,因為當初找到的幾篇部落格都大同小異,沒有提到這種場景,官網看了下,奈何全是英文,就自個研究了下原始碼,這就是傳說中的自己坑自己吧!後來也有看到別的博文介紹哨兵叢集時tomcat conf.xml的設定,去官網上也看到了相關的設定說明。不過我弄的時候沒看到啊,暈!塞翁失馬焉知非福,雖然也不知道研究了下原始碼得到了啥收穫。。。。

要了解多個的設定,首先看看原始碼中怎麼讀取單個host,port等設定引數的,找找看:

719行,新建JedislPool用到了咱們組態檔裡的引數,看看else另一個條件,那個sentinel單詞不就是哨兵麼,看看裡面相關的sentinelMaster,sentinelSet的get、set方法,

sentinelMaster需要傳個master,sentinelSet需要傳個sentinels,顧名思義,master是主節點名稱,sentinels是各個節點的連線資訊,抱著試一試的態度,在context.xml組態檔中又加上倆引數。

同樣:這裡預設Redis叢集模式已經更改為哨兵模式且正常執行(Redis哨兵叢集這裡就不贅述了)。

sentinelMaster="mymaster"

sentinels="127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381"

新增引數說明:

sentinelMaster:master名稱

sentinels:哨兵叢集時地址設定,IP:port,用英文逗號隔開

然後重新啟動兩個tomcat,接下來繼續驗證:驗證方式和上面一樣,當上面兩個步驟驗證完後,將當前主節點手工關掉,然後再次重新整理瀏覽器驗證,發現sessionId依然有效,至此,已經成功百分之九十了。

過期時間

剩下的百分之十,就是session過期的問題了。在啟動tomcat時,會有個警告

說明那個maxInactiveInterval引數設定有點問題。出問題了,那就原始碼裡看看啥情況,找到原始碼中設定session超時時間的地方,在RedisSessionManager類中,377和545行還有632行,這個時間值都用到的getMaxInactiveInterval()方法,如下

再看看getMaxInactiveInterval()方法

看到這兒似乎明白了,本專案中並不是根據我們的組態檔中引數賦值,這個時間設定的值取的是Tomcat容器的session-timeout 節點(單位min),更改tomcat  conf/web.xml設定,約595行

<session-config>

        <session-timeout>10</session-timeout>

</session-config>

去掉組態檔中的maxInactiveInterval引數,更改web.xml 中session-timeout時間為2分鐘,重新啟動Tomcat測試session失效場景,驗證成功,至此Tomcat8.5整合Redis 解決Session對談共用問題算是大功告成!

謹記,官方檔案很重要!很重要!很重要!仔細看看會少走很多彎路!

以上內容均為個人對別人成果的學習和總結,有理解不到位的地方,還請各路大神指點!

原創不易,看了覺得有幫助的朋友們,記得點個贊喲,謝謝!