Nginx學習——session共享(二)
上一篇博文說到了nginx session共享問題。由於 nginx 是隨機分配請求,假設一個使用者登入時訪問網站登入時被分配到 192.168.43.3:8080 上,然後進行了登入操作,此時該伺服器上就會有該使用者登入的 session 資訊,然後登陸後重定向到網站首頁或個人中心時,此時如果被分配到 192.168.43.3:8081 上,那麼這臺伺服器上沒有該使用者 session 資訊,於是又會變成未登入狀態,所以由於 nginx 的負載均衡會導致 session 共享的問題。
不使用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的安全性不高,雖然它已經加了密,但是還是可以偽造的。session存在資料庫(MySQL等)中
java可以配置將session儲存在資料庫中,這種方法是把存放session的表和其他資料庫表放在一起,如果mysql也做了叢集了話,每個mysql節點都要有這張表,並且這張session表的資料表要實時同步。
說明:用資料庫來同步session,會加大資料庫的IO,增加資料庫的負擔。而且資料庫讀寫速度較慢,不利於session的適時同步。ip_hash 策略
nginx 提供了 ip_hash 策略,可以保持使用者 ip 進行 hash 值計算固定分配到某臺伺服器上,然後只要是該 ip 則會保持分配到該伺服器上,保證使用者訪問的是同一臺伺服器,那麼 session 問題就不存在了。這也是解決 session 共享的一種方式,也稱為黏性 session。但是假設一臺 tomcat 伺服器掛了的話,那麼 session 也會丟失。所以比較好的方案是抽取 session。upstream_hash
為了解決ip_hash的一些問題,可以使用upstream_hash這個第三方模組,這個模組多數情況下是用作url_hash的,但是並不妨礙將它用來做session共享。沒試過真心的不明白session存在memcache或者redis中
此種方式將將使用者的登入資訊儲存到redis中,因為是基於記憶體的讀取,因此效率不會是響應效率的瓶頸,cookie中儲存著jsessionid,不需要加密或處理,只需要儲存redis中的key儲存統一客戶通過cookie中的key可以準確的登入資訊或是其他有效的資訊,此種方式,cookie的儲存不需要加密計算成本,其次redis將資訊儲存到快取中,存取效率高,後面會詳細介紹此種方式實現過程。基於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" />
- 下載tomcat-juli.jar
環境為 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.jar和tomcat-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 : 修改配置檔案的時候,一定要先備份再修改,不然出了問題都不能恢復。