通常來講,咱們在java中都經過以下代碼進行用戶登陸後的服務端註冊,而且在用戶下次請求時無需再登錄一遍,這就是Servlet的Session。使用了這種Session策略,那麼Web容器好比tomcat就爲當前用戶生成一個SessionID,而且以這個SessionID爲索引,存儲這個用戶相關的鍵值對,好比用戶名,登錄時間一類的。存儲在服務器的內存中。同時再response裏向用戶瀏覽器中設置一個cookie,這個cookie的名字爲jsessionid,內容爲服務器生成的隨機數SessionID。在用戶第二次請求時,將這個cookie發給服務器,服務器根據這個SessionID到內存中尋找相關數據,把用戶名什麼的提取出來,服務器就能夠在原本無狀態的HTTP鏈接中識別出這是哪一個客戶發出的請求,而後繪製相關頁面。
這中Session機制使用簡單方便,被使用了很長時間。可是一旦作成集羣,這種方式就不靈了。以NGINX默認的輪詢方式爲例,用戶在A服務器上登錄成功,SessionID和用戶名等相關信息寫入了A服務器的內存中,該用戶第二次請求時被NGINX分發到了B服務器,而B服務器沒用該用戶的SessionID和用戶名等相關信息,因而要求用戶再登錄一遍。用戶第二次登錄以後發送第三次請求,被NGINX分配到了A或者C服務器,因而用戶又必須登錄一遍,總之這個用戶一直無法登錄成功。
php
基於以上現象,有幾種存儲session 的方法,以下:html
1. 數據庫存儲sessionjava
2.使用 memcached,redis等存儲sessionnginx
3. 使用nginx 內置模塊,ip_hashweb
4. 使用cookie的HASH來區分同一個用戶的不一樣連接redis
前面咱們已經知道了若是使用Servlet Session的話,Web容器會自動的在用戶瀏覽器上創建名爲jsessionid的cookie,而且值就是服務器端的SessionID。另外一方面,新版的NGINX不光能夠經過IP的hash來分發流量,也能夠經過url的hash,cookie的hash,header的hash等等進行連接的固定分配。因爲用戶登錄成功之後名爲jsessionid的cookie就有了一個短時間固定的值,並且每一個用戶都不同,那麼咱們就能夠根據這個sessionid的hash值爲它分配一個服務器。在當前sessionID起做用的時候那麼分配的服務器也是同一個,而且不須要安裝第三方的插件。數據庫
本次使用第4種方法,使用cookie 是用戶分配的服務器是同一個。nginx 配置以下:瀏覽器
[root@www vhosts]# cat load.conf tomcat
upstream tomcat_server { 服務器
hash $cookie_jsessionid;
# hash $request_uri;
server 172.16.31.16:8080;
server 172.16.31.17:8080;
}
#error_page配置備份:
upstream backup {
server 11.11.11.14:80; }
error_page 404 500 502 503 504 =200 @fetch; #注意:=200裏的等號,左邊有空格,右邊沒空格
server {
listen 80;
server_name www.load.com;
root /data/wwwroot/www.load.com;
index index.html index.htm index.php;
access_log /usr/local/nginx/logs/www.load.com-access.log gufan;
error_log /usr/local/nginx/logs/www.load.com-error.log;
location /stat {
proxy_pass
http://tomcat_server;
proxy_set_header
Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_intercept_errors on;
proxy_next_upstream off;
}
location @fetch {
proxy_pass http://backup;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}