1. 程式人生 > >Nginx學習——session共享(二)

Nginx學習——session共享(二)

上一篇博文說到了nginx session共享問題。由於 nginx 是隨機分配請求,假設一個使用者登入時訪問網站登入時被分配到 192.168.43.3:8080 上,然後進行了登入操作,此時該伺服器上就會有該使用者登入的 session 資訊,然後登陸後重定向到網站首頁或個人中心時,此時如果被分配到 192.168.43.3:8081 上,那麼這臺伺服器上沒有該使用者 session 資訊,於是又會變成未登入狀態,所以由於 nginx 的負載均衡會導致 session 共享的問題。

  1. 不使用session,換用cookie
    session是存放在伺服器端的,cookie是存放在客戶端的,我們可以把使用者訪問頁面產生的session放到cookie裡面,就是以cookie為中轉站。你訪問web伺服器A,產生了session然後把它放到cookie裡面,當你的請求被分配到B伺服器時,伺服器B先判斷伺服器有沒有這個session,如果沒有,再去看看客戶端的cookie裡面有沒有這個session,如果也沒有,說明session真的不存,如果cookie裡面有,就把cookie裡面的sessoin同步到伺服器B,這樣就可以實現session的同步了。
    說明:這種方法實現起來簡單,方便,也不會加大資料庫的負擔,但是如果客戶端把cookie禁掉了的話,那麼session就無從同步了,這樣會給網站帶來損失;cookie的安全性不高,雖然它已經加了密,但是還是可以偽造的。

  2. session存在資料庫(MySQL等)中
    java可以配置將session儲存在資料庫中,這種方法是把存放session的表和其他資料庫表放在一起,如果mysql也做了叢集了話,每個mysql節點都要有這張表,並且這張session表的資料表要實時同步。
    說明:用資料庫來同步session,會加大資料庫的IO,增加資料庫的負擔。而且資料庫讀寫速度較慢,不利於session的適時同步。

  3. ip_hash 策略
    nginx 提供了 ip_hash 策略,可以保持使用者 ip 進行 hash 值計算固定分配到某臺伺服器上,然後只要是該 ip 則會保持分配到該伺服器上,保證使用者訪問的是同一臺伺服器,那麼 session 問題就不存在了。這也是解決 session 共享的一種方式,也稱為黏性 session。但是假設一臺 tomcat 伺服器掛了的話,那麼 session 也會丟失。所以比較好的方案是抽取 session。

  4. upstream_hash
    為了解決ip_hash的一些問題,可以使用upstream_hash這個第三方模組,這個模組多數情況下是用作url_hash的,但是並不妨礙將它用來做session共享。沒試過真心的不明白

  5. session存在memcache或者redis中
    此種方式將將使用者的登入資訊儲存到redis中,因為是基於記憶體的讀取,因此效率不會是響應效率的瓶頸,cookie中儲存著jsessionid,不需要加密或處理,只需要儲存redis中的key儲存統一客戶通過cookie中的key可以準確的登入資訊或是其他有效的資訊,此種方式,cookie的儲存不需要加密計算成本,其次redis將資訊儲存到快取中,存取效率高,後面會詳細介紹此種方式實現過程。

  6. 基於tomcat容器session
    此種方式在根本上實現共享session,他的實際情況是通過tomcat管理配置將一個tomct下的session複製到其他的tomcat的session池中,實現真實上的session共享;此種方式需要相容tomcat配置及需要對其進行擴充套件,依賴性太強。

一:Redis 環境搭建

redis 依賴 gcc,先安裝:

yum install -y gcc-c++

下載 redis,我使用的是 redis-3.2.11.tar.gz,上傳至 linux /usr/local/redis-src / 中,解壓

進入解壓後目錄 redis-3.2.11,執行 make 命令進行編譯

安裝到目錄 /usr/local/redis

執行:

make PREFIX=/usr/local/redis install

安裝完成之後將 redis 配置檔案拷貝到安裝目錄下,redis.conf 是 redis 的配置檔案,redis.conf 在 redis 原始碼目錄, port 預設 6379。
執行命令:

cp /root/wyj/tools/redis/redis-3.2.11/redis.conf /usr/local/redis/

在 redis 安裝目錄啟動和關閉 redis:

啟動:
這裡寫圖片描述
這種啟動方式叫做前端啟動,必須保持在當前視窗,如果 ctrl + c 退出,那麼 redis 也就退出了,不建議使用

那麼後端啟動:

首先修改 redis.conf 中 daemonize 的值,開啟可以看到預設是 no,修改為 daemonize yes,啟動即可。也可以在該配置檔案中修改 redis 預設埠 6379 為其他值。
這裡寫圖片描述

./bin/redis-cli shutdown

至此,redis 伺服器搭建完成。

二:下載相關jar

  • 環境為 tomcat7 + jdk1.6 :
    在所有需要共享 session 的伺服器的 tomcat 中目錄下:

    lib 目錄中新增以下五個 jar 包,注意版本最好一致,不然極容易出現錯誤,下邊的測試是可用的:

    • 下載tomcat-juli.jar
      這裡寫圖片描述
      conf 目錄中 content.xml 中加入:配置 redis 服務
      <Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve"/> 
      <Manager className="com.radiadesign.catalina.session.RedisSessionManager"
      host="localhost"
      port="6379"
      database="0"  
      maxInactiveInterval="60" />
      
  • 環境為 tomcat7 + jdk1.7 或 1.8 :
    在所有需要共享 session 的伺服器的 tomcat 中目錄下:

    lib 目錄中新增以下五個 jar 包,其中tomcat-redis-session-manager.jar需要重新下載編譯打包,不然會報錯

    conf 目錄中 content.xml 中加入:配置 redis 服務

    <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />       
    <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
    host="localhost"  
    port="6379"  
    database="0"              
    maxInactiveInterval="60"/>
    

三:配置Tomcat

根據我這測試,是 jkd1.8+tomcat7,在 137 和 139 兩臺 tomcat 中加入 jar 包且進行如上配置:

上傳 jar 包
這裡寫圖片描述
這裡寫圖片描述
修改 content.xml
這裡寫圖片描述
啟動 redis 服務,重新啟動所有 tomcat,啟動 nginx,重新整理 nginx 頁面, 兩臺 tomcat 頁面可以看到 sessionid 值不變,關閉某臺 tomcat,nginx 中 sessionid 不變,說明 session 是共享的。

請注意!!!!

context.xml 配置說明:

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />      
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
//這裡是redis伺服器地址
host="localhost"
//這裡是redis埠,redis預設埠是6379
port="6379"
//這裡是redis資料庫中的標識,標識第0個,預設使用0即可
database="0"            
//需要注意的是這裡由於redis過期時間預設設定為60,單位是秒,session過期時間為30分鐘,所以需要設定為1800對應30分鐘
maxInactiveInterval="1800"/>

四:專案搭建中遇到的問題

將相關commons-pool2-2.4.1.jar,tomcat-redis-session-manager-1.2-tomcat-7-java-7.jar,jedis-2.6.2.jar,放到comcat的lib目錄下,啟動後報錯:
這裡寫圖片描述

檢視下載的包tomcat-redis-session-manager-1.2-tomcat-7-java-7.jar或tomcat-redis-session-manager-1.2-tomcat-7.jar相關包的裡面並沒有類:com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve。
https://github.com/jcoleman/tomcat-redis-session-manager 直接下載原始碼,發現原始碼裡面存在相應的類。同時原始碼(tomcat-redis-session-manager)依賴了tomcat其他的包:tomcat-juli.jar,而tomcat預設是沒有這些包的,從 https://mirrors.cnnic.cn/apache/tomcat/tomcat-7/v7.0.82/bin/extras/ 下載tomcat-juli-adapters.jartomcat-juli.jar兩個包,放在apache-tomcat-7.0.82\lib目錄下,同時將tomcat-juli.jar放在apache-tomcat-7.0.82\bin目錄下同時將編譯tomcat-redis-session-manager的原始碼,通過相應的依賴包common-pool2.2,jedis以及tomcat-juli.jar編譯,並打成自己的jar包。
打包詳情如下:
這裡寫圖片描述
點選 http://download.csdn.net/download/wangyuanjun008/10214996 下載
總結
這篇文章寫下來可真是費了些力氣,中間出了好多錯,不過一個一個有耐心的解決掉,最後出來的結果還是令人挺有成就感的。畢竟心裡的一塊大石算是落了。以後有空再嘗試一下其他幾種方法。

PS : 修改配置檔案的時候,一定要先備份再修改,不然出了問題都不能恢復。