session共享方案
****背景:HTTP協議是無狀態的,為了記錄用戶的一些基本信息避免每次請求都需要驗證用戶是性能變差。客戶端和服務器端基於該缺點分別做了相應的機制:cookie和session機制。但是將tomcat部署在集群中時,需要多臺服務器的session保持一致,及session共享否則容易出現登錄的用戶在另一臺服務器出現無登陸的狀況,該文章將針對該問題進行研究。
****總體方案及分析:
目前解決session共享的方案有三種方案:
一 cookie機制
原理:
該方法就是將session中保存的信息加密後全部返回給客戶端的cookie中,這樣客戶端每次發送請求時會將這些信息發送給服務器端,同一用戶在不同的服務器上cookie是一樣的因此不會出現session共享的問題。
優勢:
該方案比較簡單,容易實現,服務器的壓力減小。
缺點:
1.因將很多信息存在cookie中,客戶端每次請求需要將cookie中的信息傳送給服務器端,所以網絡請求資源占用比較多,(服務器購買帶寬是一個很大費用),成本增高。歸納為帶寬性能,速度問題。
2.不同的瀏覽器對cookie的存儲大小限制不同。
3.安全性問題,session中存的都是重要性數據(賬號、昵稱、用戶ID等),存在著泄露風險。
適用性:
基於上述優缺點的分析該方案適用於存儲信息量比較少的,但不適用高訪問量的情況下,每次請求瀏覽器都要發送session數據給服務器。一般一個Cookie大小2K的樣子。
二 負載均衡
原理:
將某一用戶按照一定的規則固定的分發到同一服務器,每次請求都命中同一臺服務器,因此不涉及session共享。
優點:
簡單容易實現,直接在服務器進行配置,不需要在代碼層上做限制。
缺點:
1.負載均衡的目的:當其中的服務器不可用時,會自動的分發到可用的機子上去。然而經過上述的規則後,只要一臺服務器故障後,那麽所有命中該臺服務器的用戶將無法登錄。
三 將session信息存入中間層
基本原理:
將session信息存到某一中間層,所有的應用從該中間層獲取用戶的基本信息。
其中cookie機制比較簡單將用戶信息經過加密後寫入cookie中,每次請求服務器端需要從cookie中獲取信息驗證用戶。現將對其他的兩種方案做詳細的研究。
****方案詳解
一 負載均衡
1.nginx反向代理與負載均衡
架構圖
該負載均衡用到三臺服務器,一臺nginx服務器,兩臺正式部署項目的服務器,首先在部署項目的兩臺服務器上部署項目的tomcat,並啟動tomcat。配置防火墻端口:vim/etc/sysconfing/iptables編輯,開放8080、80端口等一些常用的端口,以及後邊用到的端口都需要配置開放,不建議關閉防火墻。
2.反向代理與負載均衡配置
3.nginx負載均衡策略
所以多個項目的實例中不出現session錯亂的現象,nginx需要同一用戶每次命中同一臺服務器,需要采用ip_hash的負載均衡的模式。但是如果項目的前面還有其他的服務器進行轉發的話就需要我們自定義負載均衡策略,首先獲取用戶的真實IP,然後將該ip進行映射到同一服務器。
添加的配置如下:
1.1在http{}中添加
http {
include mime.types;
default_type application/octet-stream;
client_max_body_size 50m;
client_body_buffer_size 256k;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
proxy_buffer_size 64k;
proxy_buffers 32 32k;
proxy_busy_buffers_size 128k;
proxy_connect_timeout 600;
proxy_read_timeout 600;
proxy_send_timeout 600;
#獲取用戶真實IP,並賦值給變量$clientRealIP
map $http_x_forwarded_for $clientRealIp {
“” $remote_addr;
~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
}[S1]
[S1]獲取用戶的真實ip
1.2.添加upstream
upstream app1{
hash $clientRealIp;[S1]
server swh.**.com:8114[S2] ;
server swh1.**.com:8116;[S3]
}
[S1]自定義hash:根據用戶真實ip進行hash
[S2]雙節點機器名1:端口號
[S3]雙節點機器名2:端口號
1.3 在server{}中添加
server {
listen 8888;
server_name swh.**.com localhost;
proxy_redirect http://test1.**.com/ http://test2.**.com/;
server_name_in_redirect on;
location /app1{
#proxy_pass http://swh.**.com:8114/app1;
add_header realIP $remote_addr;
add_header REMOTE_IP $http_remote_addr;
add_header clientRealIp $clientRealIp;
add_header X-Forwarded-For-1 $http_x_forwarded_for;
add_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header backendIP $upstream_addr;
add_header backendCode $upstream_status;
proxy_read_timeout 120;
proxy_set_header Host $http_host;
proxy_set_header Remote-Addr $http_remote_addr;
access_log logs/app1.access.log main;
error_log logs/app1.error.log;
if ($remote_addr = ‘192.33.12.3‘)
{
proxy_pass http://swh.**.com:8114;
break;
}
if ($remote_addr = ‘192.32.5.9‘)
{
proxy_pass http://swh1.baidu.com:8116;
break;
}
proxy_pass http://app1/app1;
}
location /mobile {
add_header clientRealIp $clientRealIp; // 在消息頭中添加信息(命中的服務器的名稱:端口號)
add_header backendIP $upstream_addr;
add_header backendCode $upstream_status;
proxy_pass http://mobile[S1] /mobile;
proxy_read_timeout 120;
proxy_set_header clientRealIp $clientRealIp;
proxy_set_header Host $http_host;
proxy_set_header Remote-Addr $http_remote_addr;
access_log logs/mobile.access.log main;
error_log logs/mobile.error.log;
}
}
}
[S1]與upstream名保持一致
二.將session信息存入中間層
(1)nginx提供了ip_hash策略,可以保持用戶ip進行hash值計算固定分配到某臺服務器上,然後只要是該ip則會保持分配到該服務器上,保證用戶訪問的是同一臺服務器上,那麽session問題就不存在了。這也是解決session共享的一種方式,也稱為黏性session。但是假設一臺tomcat服務器掛了,那麽session也會失效。所以比較好的方案是抽取session。
(2)session存在redis或者memcache,以這種方式來同步session,把session抽取出來,放到內存數據庫裏,解決了session共享的問題,同時讀取速度也是非常之快。
session共享方案