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


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

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

一、正向代理和反向代理

 1、正向代理的概念

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

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

  2、反向代理的概念

  繼續舉例:

  例用戶訪問 http://ooxx.me/readme,但ooxx.me上並不存在readme頁面,他是偷偷從另外一台服務器上取回來,然后作為自己的內容吐給用戶,但用戶並不知情。這很正常,用戶一般都很笨。這里所提到的 ooxx.me 這個域名對應的服務器就設置了反向代理功能。

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

  3、兩者區別

  從用途 上來講:

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

   反向代理的典型用途是將 防火牆后面的服務器提供給Internet用戶訪問;反向代理還可以為后端的多台服務器提供負載平衡,或為后端較慢的服務器提供緩沖服務。

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

    從安全性 來講:

   正向代理允許客戶端通過它訪問任意網站並且隱藏客戶端自身,因此你必須采取安全措施以確保僅為經過授權的客戶端提供服務;

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

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

  

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

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

  1、什么是負載均衡?

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

  負載均衡建立在現有網絡結構之上,它提供了一種廉價有效透明的方法擴展網絡設備和服務器的帶寬、增加吞吐量、加強網絡數據處理能力、提高網絡的靈活性和可用性。負載均衡,核心就是網絡流量分發,分很多維度。從網絡層看,基本是四層(TCP,UDP),和七層(HTTP,HTTPS等),基本就是解析到對應的網絡層,然后根據不同特征分發。比如四層的,基本就是根據連接信息(TCP)或者本身的特征(源IP,目標IP)等做。七層的,就可以用域名(HTTP頭里的Host),URL,Cookie,Header這些來做。

  2、負載均衡的分類

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

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

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

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

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

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

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

  nginx負載均衡服務器:192.168.3.43

  tomcat1服務器:192.168.3.43:8080

  tomcat2服務器:192.168.3.43:8081

  4、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;
        }
    }

  這樣的情況下,就反向代理成功了。會出現兩個端口下的頁面輪詢。那么負載均衡體現在哪里呢?

  5、負載均衡的策略

  上面的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次失敗后,暫停的時間

三、分布式下session保持

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

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

  1、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如何才能實現同步?

  2、分布式的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
  



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM