Nginx如何實現負載均衡以及Session共享教程詳解

最近迷上了Nginx,真實麻雀雖小,五臟俱全..功能實在強大..php

nginx不單能夠做爲強大的web服務器,也能夠做爲一個反向代理服務器,並且nginx還能夠按照調度規則實現動態、靜態頁面的分離,能夠按照輪詢、ip哈希、URL哈希、權重等多種方式對後端服務器作負載均衡,同時還支持後端服務器的健康檢查。html

若是隻有一臺服務器時,這個服務器掛了,那麼對於網站來講是個災難.所以,這時候的負載均衡就會大顯身手了,它會自動剔除掛掉的服務器.前端

下面簡單的介紹下我使用Nginx作負載的體會nginx

下載---安裝Nginx這些不介紹了,前篇有介紹.web

windows和Linux下配置Nginx負載的寫法同樣,故不分開介紹.redis

Nginx負載均衡一些基礎知識:數據庫

nginx 的 upstream目前支持 4 種方式的分配
1)、輪詢(默認)windows

每一個請求按時間順序逐一分配到不一樣的後端服務器,若是後端服務器down掉,能自動剔除。

2)、weight後端

指定輪詢概率,weight和訪問比率成正比,用於後端服務器性能不均的狀況。

2)、ip_hash瀏覽器

每一個請求按訪問ip的hash結果分配,這樣每一個訪客固定訪問一個後端服務器,能夠解決session的問題。

3)、fair(第三方)

按後端服務器的響應時間來分配請求,響應時間短的優先分配。

4)、url_hash(第三方)

配置:

在http節點裏添加:
定義負載均衡設備的 Ip及設備狀態
upstream myServer {

server 127.0.0.1:9090 down; 
server 127.0.0.1:8080 weight=2; 
server 127.0.0.1:6060; 
server 127.0.0.1:7070 backup;

}
在須要使用負載的Server節點下添加
proxy_pass http://myServer;
upstream 每一個設備的狀態:
down 表示單前的server暫時不參與負載
weight 默認爲1.weight越大,負載的權重就越大。
max_fails :容許請求失敗的次數默認爲1.當超過最大次數時,返回proxy_next_upstream 模塊定義的錯誤
fail_timeout:max_fails 次失敗後,暫停的時間。
backup: 其它全部的非backup機器down或者忙的時候,請求backup機器。因此這臺機器壓力會最輕。

Nginx還支持多組的負載均衡,能夠配置多個upstream 來服務於不一樣的Server.

配置負載均衡比較簡單,可是最關鍵的一個問題是怎麼實現多臺服務器之間session的共享

下面有幾種方法(如下內容來源於網絡,第四種方法沒有實踐.)

1) 不使用session,換做cookie

能把session改爲cookie,就能避開session的一些弊端,在從前看的一本J2EE的書上,也指明在集羣系統中不能用session,不然惹出禍端來就很差辦。若是系統不復雜,就優先考慮可否將session去掉,改動起來很是麻煩的話,再用下面的辦法。

2) 應用服務器自行實現共享

asp.net能夠用數據庫或memcached來保存session,從而在asp.net自己創建了一個session集羣,用這樣的方式能夠令 session保證穩定,即便某個節點有故障,session也不會丟失,適用於較爲嚴格但請求量不高的場合。可是它的效率是不會很高的,不適用於對效率 要求高的場合。
以上兩個辦法都跟nginx沒什麼關係,下面來講說用nginx該如何處理:

3) ip_hash

nginx中的ip_hash技術可以將某個ip的請求定向到同一臺後端,這樣一來這個ip下的某個客戶端和某個後端就能創建起穩固的session,ip_hash是在upstream配置中定義的:
upstream backend {
server 127.0.0.1:8080 ;
server 127.0.0.1:9090 ;
ip_hash;
}
ip_hash是容易理解的,可是由於僅僅能用ip這個因子來分配後端,所以ip_hash是有缺陷的,不能在一些狀況下使用:
1/ nginx不是最前端的服務器。ip_hash要求nginx必定是最前端的服務器,不然nginx得不到正確ip,就不能根據ip做hash。譬如使用的是squid爲最前端,那麼nginx取ip時只能獲得squid的服務器ip地址,用這個地址來做分流是確定錯亂的。
2/ nginx的後端還有其它方式的負載均衡。假如nginx後端又有其它負載均衡,將請求又經過另外的方式分流了,那麼某個客戶端的請求確定不能定位到同一臺session應用服務器上。這麼算起來,nginx後端只能直接指向應用服務器,或者再搭一個squid,而後指向應用服務器。最好的辦法是用location做一次分流,將須要session的部分請求經過ip_hash分流,剩下的走其它後端去。

4) upstream_hash

爲了解決ip_hash的一些問題,可使用upstream_hash這個第三方模塊,這個模塊多數狀況下是用做url_hash的,可是並不妨礙將它用來作session共享:
假如前端是squid,他會將ip加入x_forwarded_for這個http_header裏,用upstream_hash能夠用這個頭作因子,將請求定向到指定的後端:
可見這篇文檔: http://www.sudone.com/nginx/nginx_url_hash.html
在文檔中是使用$request_uri作因子,稍微改一下:
hash $http_x_forwarded_for;
這樣就改爲了利用x_forwarded_for這個頭做因子,在nginx新版本中可支持讀取cookie值,因此也能夠改爲:
hash $cookie_jsessionid;
假如在php中配置的session爲無cookie方式,配合nginx本身的一個userid_module模塊就能夠用nginx自發一個cookie,可參見userid模塊的英文文檔:
http://wiki.nginx.org/NginxHttpUserIdModule
另可用姚偉斌編寫的模塊upstream_jvm_route: http://code.google.com/p/nginx-upstream-jvm-route/

===============================================

https://blog.csdn.net/chao_1990/article/details/54405759

共享session應用場景,基於分佈式,session的原理大體以下(以tomcat爲例),

tomcat有一套本身的session管理機制,每次建立鏈接的時候都會經過客戶端傳過來的jsessionid從session鏈接池中得到sessionId對應的session,若是存在,那麼直接從池中得到session鏈接信息,若是沒有經過程序中設置判斷是否建立一個新的session信息保存到池中。

nginx貢獻session的方式,大致上有ip_hash(nginx自帶),redis共享session,基於cookie,基於db(各類關係型數據庫和非關係型數據庫)。

一、基於cookie

簡單、方便,每次經過判斷cookie中的用戶狀態信息判斷用戶的登陸狀態;可是用戶信息要存在客戶端,存在安全隱患,除非有至關安全的加密措施,若是加密碼負載,也會 增長運算的成本。

二、基於db(各類關係型數據庫和非關係型數據庫)

登陸信息存儲到db中,雖然安全,但每次須要驗證用戶的登陸狀態是都須要從db中進行IO操做,併發量高是勢必會增長數據庫的負載。

三、基於redis+cookie共享session

此種方式將將用戶的登陸信息存儲到redis中,由於是基於內存的讀取,所以效率不會是響應效率的瓶頸,cookie中存儲着jsessionid,不須要加密或處理,只須要存儲redis中的key保存統一客戶經過cookie中的key能夠準確的登陸信息或是其餘有效的信息,此種方式,cookie的存儲不須要加密計算成本,其次redis將信息存儲到緩存中,存取效率高,後面會詳細介紹此種方式實現過程。

四、基於ip_hash

此種方式配置最爲簡單,可是有必定的侷限性,其原理就是同一個ip的全部請求都會被nginx進行ip_hash進行計算,經過結果定位到指定的後臺服務器即一個用戶若是ip不變,那麼每次請求其實請求的都是同一後臺服務器;首先最外層的代理要保證源ip在請求 的過程不會被修改,若是你的架構裏在最外層方式不僅僅是nginx服務,而是相似於請求分發的服務服務器,那麼意味着一我的的請求可能被定位到不一樣的服務器上,那麼ip_hash就沒有意義了。

五、基於tomcat容器session

此種方式在根本上實現共享session,他的實際狀況是經過tomcat管理配置將一個tomct下的session複製到其餘的tomcat的session池中,實現真實上的session共享;此種方式須要兼容tomcat配置及須要對其進行擴展,依賴性太強。

已實現的共享方式:

首先配置3個web容器,tomcat1(3301),tomcat2(3302)、tomcat3(3303)

一、ip_hash

nginx的配置這裏再也不說明,主要說明ip_hash的配置,簡直是簡單到節點

  1. upstream backend {
  2. ip_hash;
  3. server localhost:3301 max_fails=2 fail_timeout=30s ;
  4. server localhost:3302 max_fails=2 fail_timeout=30s ;
  5. server localhost:3303 max_fails=2 fail_timeout=30s ;
  6. }

nginx的配置文件nginx.conf引入upstram數據,啓動便可。

驗證:

過訪問web應用,例如http://localhost:8080/login.jsp登陸後存儲session信息,每次訪問這個頁面都須要驗證session的狀態,頁面實現的是tomcat1表示,此ip的請求被轉發到了tomcat1的服務器上,不管怎麼刷新頁面,頁面顯示的都是tomcat1,此時停掉tomcat1,再次刷新頁面,頁面顯示的是tomcat2或是tomcat3的登陸頁面,此時表示nginx負載目的已經達到,可是session沒有共享;侷限性顯而易見。

二、redis+cookie共享session

原理實現:

1)、登陸成功時,將還有redis的key保存到cookie中,將登陸用戶的信息保存到redis中;

2)、配置攔截器,攔截須要驗證登陸狀態的請求,從cookie中得到redis的key,從redis中得到當前cookie對應的用戶信息,對其登陸狀態進行驗證。

驗證:

取消nginx的ip_hash配置,登陸web,例如例如http://localhost:8080/login.jsp登陸後存儲session信息,首頁顯示tomcat1,此時不須要關閉任何tomcat,直接不停的刷新主頁就會發現主頁的再tomcat一、tocmat二、tomcat3之間來回切換,表示session已正常共享。我的認爲此種方式是比較推薦的。

觀點:

從功能的核心來看,其目的就是共享session,究其緣由就是客戶端和服務之間須要一個惟一的值來創建關聯關係,此值就是sessionId,不管請求哪一個網站經過工具查看cookie都會有發現,有jsessionid的值,此值在於服務器創建鏈接之後是基本不會變的(後臺主動建立新的session)。及時上面的描述的共享方式5,基於session鏈接池的session管理,也是要依賴sessionid的,經過查看tomcatsession管理的源碼,不難發現其也是經過cookie得到的sessionid,那麼若是客戶端請強制禁用了cookie,該如何得到jsessionId? 以前查閱過資源(未親自證明),當瀏覽器禁用cookie後,請求的地址會被重定向,重定向後會在請求的url中拼接上jsessionid,這個容器就能得到sessionid,也就能夠驗證session 狀態;此種場景有待證明。

往期文章

Nginx系列教程(1)nginx基本介紹和安裝入門
Nginx系列教程(2)nginx搭建靜態資源web服務器
Nginx系列教程(3)nginx緩存服務器上的靜態文件
Nginx系列教程(4)nginx處理web應用負載均衡問題以保證高併發
Nginx系列教程(5)如何保障nginx的高可用性(keepalived)
Nginx系列教程(6)nginx location 匹配規則詳細解說
Nginx系列教程(7)nginx rewrite配置規則詳細說明
Nginx系列教程(8)nginx配置安全證書SSL
Nginx系列教程(9)nginx 解決session一致性

相關文章
相關標籤/搜索