nginx反向代理、負載均衡以及分佈式下的session保持

【前言】部署服務器用到了nginx,相比較於apache併發能力更強,優勢也比其多得多。雖然個人項目可能用不到這麼多性能,仍是部署一個流行的服務器吧!html

  此篇博文主要學習nginx(ingine x)的反向代理、負載均衡原理,並介紹一下分佈式下sesssion保持。(分佈式和集羣的區別?下面有)java

1、正向代理和反向代理

 一、正向代理的概念

  正向代理,也就是傳說中的代理,他的工做原理就像一個跳板,簡單的說,我是一個用戶,我訪問不了某網站,可是我能訪問一個代理服務器。這個代理服務器呢,他能訪問那個我不能訪問的網站因而我先連上代理服務器,告訴他我須要那個沒法訪問網站的內容,代理服務器去取回來,而後返回給我。從網站的角度,只在代理服務器來取內容的時候有一次記錄,有時候並不知道是用戶的請求,也隱藏了用戶的資料,這取決於代理告不告訴網站。linux

   結論就是 正向代理 是一個位於客戶端和原始服務器(origin server)之間的服務器,爲了從原始服務器取得內容,客戶端向代理髮送一個請求並指定目標(原始服務器),而後代理向原始服務器轉交請求並將得到的內容返回給客戶端。客戶端必需要進行一些特別的設置才能使用正向代理。nginx

  二、反向代理的概念

  繼續舉例:web

  例用戶訪問 http://ooxx.me/readme,但ooxx.me上並不存在readme頁面,他是偷偷從另一臺服務器上取回來,而後做爲本身的內容吐給用戶,但用戶並不知情。這很正常,用戶通常都很笨。這裏所提到的 ooxx.me 這個域名對應的服務器就設置了反向代理功能。redis

   結論就是 反向代理正好相反,對於客戶端而言它就像是原始服務器,而且客戶端不須要進行任何特別的設置。客戶端向反向代理 的命名空間(name-space)中的內容發送普通請求,接着反向代理將判斷向何處(原始服務器)轉交請求,並將得到的內容返回給客戶端,就像這些內容 本來就是它本身的同樣。算法

  三、二者區別

  從用途 上來說:數據庫

   正向代理的典型用途是爲在防火牆內的局域網客戶端提供訪問Internet的途徑;正向代理還可使用緩衝特性減小網絡使用率。apache

   反向代理的典型用途是將 防火牆後面的服務器提供給Internet用戶訪問;反向代理還能夠爲後端的多臺服務器提供負載平衡,或爲後端較慢的服務器提供緩衝服務。後端

   另外,反向代理還能夠啓用高級URL策略和管理技術,從而使處於不一樣web服務器系統的web頁面同時存在於同一個URL空間下。

    從安全性 來說:

   正向代理容許客戶端經過它訪問任意網站而且隱藏客戶端自身,所以你必須採起安全措施以確保僅爲通過受權的客戶端提供服務;

   反向代理對外都是透明的,訪問者並不知道本身訪問的是一個代理。

2、nginx的反向代理負載均衡

  

   Nginx服務器就是反向代理服務器,只作請求的轉發,後臺有多個http服務器提供服務,nginx的功能就是把請求轉發給後面的服務器,並把結果返回給客戶端。實如今同一個域名之下,有多臺服務器,並實現服務器負載均衡。

  nginx作反向代理和後端web服務器之間的交互。

  一、什麼是負載均衡?

  負載均衡,英文名稱爲Load Balance,其意思就是算力分攤到多個操做單元上進行執行,例如Web服務器、FTP服務器、企業關鍵應用服務器和其它關鍵任務服務器等,從而共同完成工做任務。

  負載均衡創建在現有網絡結構之上,它提供了一種廉價有效透明的方法擴展網絡設備和服務器的帶寬、增長吞吐量、增強網絡數據處理能力、提升網絡的靈活性和可用性。負載均衡,核心就是網絡流量分發,分不少維度。從網絡層看,基本是四層(TCP,UDP),和七層(HTTP,HTTPS等),基本就是解析到對應的網絡層,而後根據不一樣特徵分發。好比四層的,基本就是根據鏈接信息(TCP)或者自己的特徵(源IP,目標IP)等作。七層的,就能夠用域名(HTTP頭裏的Host),URL,Cookie,Header這些來作。

  二、負載均衡的分類

  (1)從實現上看,基本能夠分軟負載均衡反向代理

  • 軟負載均衡不會過中間代理,網絡rt,性能會較好,可是通常很差作精細的流量控制,有的方案還有延時問題。實現有DNS實現,iptables實現的方案。
  • 反向代理,故名思意就是經過代理來作嗎,有中間件。因爲流量都會過LB,所以能夠作到比較精細的流量分發(好比各類權重,七層的各類轉發規則)。壞處就是代理自己可能成爲瓶頸,以及過了一層代理形成網絡延時的增長。而代理自己也會有必定成本,所以實現成本較高。
  • DNS負載均衡能夠根據地域就近分配服務器,但比較簡單使用簡單輪詢方式。有時候可搭配反向代理服務器在集羣中使用,由於在客戶端和反向代理服務器之間,能夠對多個反向代理服務器進行負載均衡。
  • 一個小結 

  (2)從實現方式看,有軟件負載均衡和硬件負載均衡:

  • 軟件負載均衡的具體軟件實現有Nginx,Haproxy,LVS,以及比較古老的Apache等,上面兩種可是軟件負載均衡。如今比較新的作法是用dpdk這種內核bypass方案作的負載均衡,因爲繞過了linux內核比較複雜的 網絡協議棧(人家自己就不是作負載均衡的。。。),所以性能會有明顯的提高(輕鬆跑滿萬兆網卡)。
  • 硬件負載均衡有大名鼎鼎的F5之類,這種不差錢的企業會採用。可是如今互聯網公司用的愈來愈少。如今硬件使用較多的是使用支持OSPF協議的交換機(基本都支持了),經過ECMP作的負載均衡集羣。這個查查雲計算廠商的負載均衡文檔,大部分都是用這個做爲分發集羣的。性能很是好(隨便幾十G器),穩定性也很高。就是貴,搭建麻煩(須要機房支持),因此不是通常用戶搞的起的。不過這個也能夠用軟件路由器(好比quagga這種)本身搭建一套軟件的OSPF集羣,不過穩定性和性能相比硬件的要大打折扣。

     每一個雲服務都會提供負載均衡服務(負載均衡服務_流量分發服務-網易雲),拿來直接用就好啦,省時又省力,能夠將更多精力放在覈心業務上面。

  三、反向代理nginx負載均衡舉例說明

    nginx做爲負載均衡服務器,用戶請求先到達nginx,再由nginx根據負載配置將請求轉發至tomcat服務器。

  nginx負載均衡服務器:192.168.3.43

  tomcat1服務器:192.168.3.43:8080

  tomcat2服務器:192.168.3.43:8081

  四、nginx配置

  upstream tomcatserver1 {
	server 192.168.3.43:8080 weight=2;
        server 192.168.3.43:8082 weight=1; #多加了此臺服務器,並增長了負載的權重。性能高的服務器作的事情多
 }
  upstream tomcatserver2 {
	server 192.168.3.43:8082;
    }
   #第一臺服務器
   server {
        listen       80;
        server_name  8080.zcinfo.com;
 
        location / {
            proxy_pass   http://tomcatserver1;
            index  index.html index.htm;
        }  
    }
  #第二臺服務器
    server {
        listen       80;
        server_name  8082.zcinfo.com;
 
        location / {
            proxy_pass   http://tomcatserver2;
            index  index.html index.htm;
        }
    }

  這樣的狀況下,就反向代理成功了。會出現兩個端口下的頁面輪詢。那麼負載均衡體如今哪裏呢?

  五、負載均衡的策略

  上面的weight大小就是一種負載均衡的策略,weight=2的會連續出現兩次,1的出現一次。總的來講,nginx提供五種負載均衡的策略。

  (1)輪詢(默認)
  每一個請求按時間順序逐一分配到不一樣的後端服務器,若是後端服務器down掉,能自動剔除。 
    upstream backserver { 
    server 192.168.0.14; 
    server 192.168.0.15; 
    } 
  (2)指定權重
  指定輪詢概率,weight和訪問比率成正比,用於後端服務器性能不均的狀況。 默認爲1
    upstream backserver { 
    server 192.168.0.14 weight=3; 
    server 192.168.0.15 weight=10; 
    } 
  (3)IP綁定 ip_hash
  每一個請求按訪問ip的hash結果分配,這樣每一個訪客固定訪問一個後端服務器,能夠解決session的問題。由於對於集羣問題很差解決session問題。
    upstream backserver { 
    ip_hash; 
    server 192.168.0.14:88; 
    server 192.168.0.15:80; 
    } 
  (4)fair(第三方)
  按後端服務器的響應時間來分配請求,響應時間短的優先分配。 
    upstream backserver { 
    server server1; 
    server server2; 
    fair; 
    } 
  (5)url_hash(第三方)
  按訪問url的hash結果來分配請求,使每一個url定向到同一個後端服務器,後端服務器爲緩存時比較有效。 
    upstream backserver { 
    server squid1:3128; 
    server squid2:3128; 
    hash $request_uri; 
    hash_method crc32; 
    }  

    6 、在須要使用負載均衡的server中增長 :

  proxy_pass http://backserver/; 
  upstream backserver{ 
    ip_hash; 
    server 127.0.0.1:9090 down;   #(down 表示單前的server暫時不參與負載) 
    server 127.0.0.1:8080 weight=2;  # (weight 默認爲1.weight越大,負載的權重就越大) 
    server 127.0.0.1:6060; 
    server 127.0.0.1:7070 backup;    # (其它全部的非backup機器down或者忙的時候,請求backup機器) 
    } 

  max_fails :容許請求失敗的次數默認爲1.當超過最大次數時,返回proxy_next_upstream 模塊定義的錯誤 
  fail_timeout:max_fails次失敗後,暫停的時間

3、分佈式下session保持

  負載均衡的應用背景下是多臺服務器,那麼對於多臺服務器這樣進行session保持呢?

  我有一篇文章已經介紹了session,此處再也不贅述。下面介紹一下session的管理,例如在java服務器下,例如tomcat服務器sessionid會以jsessionid的名稱存在cookie中,以cookie的形式和服務器通訊。

  一、session怎麼保存的?

  不一樣的服務器、不一樣的語言框架都有不一樣的實現。好比java的服務器,有的是用文件方式來存儲的;有的是用內存cache的方式來存儲的;有的語言的服務器將數據作加密,而後設置成cookie,存到了客戶端(瀏覽器)。那這些實現方式都有哪些優缺點呢?咱們逐個來分析。

  • 文件方式:這種方式,將文件做爲一個map,當新增一個數據的時候,就在文件中增長相似這樣的一條數據:
    angOwberup =>
    data={"user":{"id":1,"nickname":"老王"}};
    expiry="2016-10-0100:00:00"
    (固然,具體實現的時候有多是用的二進制方式,而不是字符串)
        這種方式的好處,就是可以存儲大量的用戶session,使得這個session有效期能夠比較長(好比:三個月用戶不用登陸)。不過這個方式也有對應的問題,就是文件操做比較麻煩。好比,有一個用戶的session過時了,須要刪掉這條記錄,那這個文件就須要挪動或重寫。

  • cache方式:有好多web端的邏輯服務器都採用這種方式。這種方式好處很是明顯,就是實現起來很是簡單。將全部數據放入到內存cache中。若是有失效,直接內存刪除就能夠了。不過帶來的問題也很明顯,當服務器重啓之後,全部session都丟失了。或者當有大量用戶登陸(也有多是遭受攻擊),就會很快讓cache被充滿,而後大量session被LRU算法淘汰,形成session的大量失效,使得用戶須要反覆登陸等操做。

  • cookie方式:這種方式是最偷懶的方式,也是我上面提的爬蟲遇到的。就是服務器任何數據都不存,把大家全部的客戶端當作個人存儲器,我就須要作一個加密和解密操做。固然這種方式最大的好處就是實現極其簡單(還有其餘的好處,稍後再說),不過問題也是很明顯的,就是客戶端要記錄大量信息,同時還要保證加密信息的安全。若是session裏要存放大數據,這種方式就不是很適合了。

  除了上述說到的優缺點之外,第一和第二,He兩種方式還有另一個問題,就是當我有不止一臺服務器的時候,不一樣服務器間的session數據共享就成問題了。好比,最初我只有一臺服務器1,他的session裏記錄了user-1和user-2的數據。這個時候,我須要增長一臺服務器2。當nginx把用戶的請求轉發到服務器2的時候,他就傻眼了:用戶帶了一個jsession_id=angOwberup這個的cookie過來,而在他的session管理器裏卻找不到這樣一個session數據。那該怎麼辦?!

  所以,就出現了咱們文章一開始提到的問題:在分佈式系統裏,用戶session如何才能實現同步?

  二、分佈式的session同步

  (PS:分佈式和集羣的區別在於分佈式解決的是壓力集中問題,每一個單元任務都不同;集羣是解決大項目臃腫問題,是同一個項目分散在不一樣單元上。因此此處用分佈式比較合適)

  有了上面的狀況,咱們就必需要去考慮,如何在多個服務器之間實現session同步這個操做。常見的作法有如下幾種,咱們逐個來看看:

  • 程間通訊傳遞session數據,這是最容易想到的一個方法。咱們在不一樣的server服務裏開一個socket,而後用socket來將相互擁有的session數據進行傳遞。我記得多年之前tomcat就是採用這樣的方式來作的(已經好久沒用過tomcat了,不知道如今是否還在這樣使用)。這種方式的好處很明顯,就是原理簡單明瞭;壞處也很明顯,就是同步合併過程複雜,還容易形成同步延遲。好比,某個用戶在server-1登陸了,server-1存儲了這個用戶的session,當正準備將數據同步給server-2的時候,因爲用戶訪問實在是太快(飛通常的速度),server-2還沒收到server-1傳來的session數據,用戶訪問就已經來了。這個時候,server-2就不能識別這個用戶,形成用戶須要再次登陸。並且,當有成千上萬臺服務器的時候,session同步就是一個噩夢:每個服務器都要將本身擁有的session廣播給其餘全部機器,並且還要隨時進行,不能停歇…… 這些機器估計都是累死的)
  • cookie存儲方式。咱們在上面講到了一個很偷懶的方式,就是把session數據作加密,而後存儲到cookie中。用戶請求到了,就直接從cookie讀取,而後作解密。這種方式真是把分佈式思想發揮到了一個至關的高度。他把用戶也當作分佈式的一員,你要訪問數據,那你就本身攜帶着他,每次到服務器的時候,咱們的服務器就只負責解密。對於session裏只存放小數據,而且加密作的比較好(防止碰撞作暴力破解)的系統來說,這是一個比較好的選擇。他實現超級簡單,並且不用考慮數據的同步。不過若是要往session裏存放大數據的狀況就不是太好處理。或者安全性要求很高的系統,也不是太好的一個方式(數據有被破解的風險)。
  • cache集羣或者數據庫作session管理。咱們也能夠採用另一種架構來解決session同步問題,那就是引入統一session接入點。咱們session放入到cache集羣(一個容易宕掉)或者數據庫中,每次請求的時候,都從他們中來獲取。這樣,全部的機器都能獲取到最新的session數據。這種方案也是不少中大型網站採用的解決方案。他實現起來相對簡單(利用cache集羣或者主從數據庫自身的管理來實現多機的互備),並且效率很高,安全性也不錯。(NFS)
  • 還有一種方式是從上面這種方式延展出來的,就是提供session服務。這個服務負責管理session,其餘服務器每次從這個服務處獲取session數據,從而達到數據的共享。
  • redis、memcache同步session。兩者能夠把web服務器中的內存組合起來,成爲一個"內存池",無論是哪一個服務器產生的sessoin均可以放到這個"內存池"中,其餘的均可以使用。不一樣之處在於redis會有固化操做。參考:https://www.cnblogs.com/lingshao/p/5580287.html
  
相關文章
相關標籤/搜索