企業級Nginx負載均衡與keepalived高可用實戰(一)Nginx篇

一、集羣簡介

1.一、什麼是集羣

  • 簡單地說,集羣就是指一組(若干個)相互獨立的計算機,利用高速通訊網絡組成的一個較大的計算機服務系統,每一個集羣節點(即集羣中的每臺計算機)都是運行各自服務的獨立服務器。這些服務器之間能夠彼此通訊,協同向用戶提供應用程序,系統資源和數據,並以單一系統的模式加以管理。當用戶客戶機請求集羣系統時,集羣給用戶的感受就是一個單一獨立的服務器,而實際上用戶請求的是一組集羣服務器。
  • 打開谷歌,百度的頁面,看起來好簡單,也許你以爲用幾分鐘就能夠製做出類似的網頁,而實際上,這個頁面的背後是由成千上萬臺服務器集羣協同工做的結果。而這麼多的服務器維護和管理,以及相互協調工做也許就是同窗們將來的工做職責了。
  • 若要用一句話描述集羣,即一堆服務器合做作同一件事,這些機器可能須要整個技術團隊架構,設計和統一協調管理,這些機器能夠分佈在一個機房,也能夠分佈在全國全球各個地區的多個機房。

1.2 爲何要使用集羣

      1. 高性能
                一些國家重要的計算密集型應用(如天氣預報,核試驗模擬等),須要計算機有很強的運算處理能力。以全世界現有的技術,即便是大型機,其計算能力也是有限的,很難單獨完成此任務。由於計算時間可能會至關長,也許幾天,甚至幾年或更久。所以,對於這類複雜的計算業務,便使用了計算機集羣技術,集中幾十上百臺,甚至成千上萬臺計算機進行計算。

        假如你配一個LNMP環境,每次只須要服務10個併發請求,那麼單臺服務器必定會比多個服務器集羣要快。只有當併發或總請求數量超過單臺服務器的承受能力時,服務器集羣纔會體現出優點。php

      2. 價格有效性
        • 一般一套系統集羣架構,只須要幾臺或數十臺服務器主機便可。與動輒價值上百萬元的專用超級計算機相比便宜了不少。在達到一樣性能需求的條件下,採用計算機集羣架構比採用同等運算能力的大型計算機具備更高的性價比。
        • 早期的淘寶,支付寶的數據庫等核心系統就是使用上百萬元的小型機服務器。後因使用維護成本過高以及擴展設備費用成幾何級數翻倍,甚至成爲擴展瓶頸,人員維護也十分困難,最終使用PC服務器集羣替換之,好比,把數據庫系統從小機結合Oracle數據庫遷移到MySQL開源數據庫結合PC服務器上來。不但成本降低了,擴展和維護也更容易了。
      3. 可伸縮性
        當服務負載,壓力增加時,針對集羣系統進行較簡單的擴展便可知足需求,且不會下降服務質量。
                一般狀況下,硬件設備若想擴展性能,不得不增長新的CPU和存儲器設備,若是加不上去了,就不得不夠買更高性能的服務器,就拿咱們如今的服務器來說,能夠增長的設備老是有限的。若是採用集羣技術,則只須要將新的單個服務器加入現有集羣架構中便可,從訪問的客戶角度來看,系統服務不管是連續性仍是性能上都幾乎沒有變化,系統在不知不覺中完成了升級,加大了訪問能力,輕鬆地實現了擴展。集羣系統中的節點數目能夠增加到幾千乃至上萬個,其伸縮性遠超過單臺超級計算機。
      4. 高可用性
        • 單一的計算機系統總會面臨設備損毀的問題,如CPU,內存,主板,電源,硬盤等,只要一個部件壞掉,這個計算機系統就可能會宕機,沒法正常提供服務。在集羣系統中,儘管部分硬件和軟件也仍是會發生故障,但整個系統的服務能夠是7*24小時可用的。
        • 集羣架構技術可使得系統在若干硬件設備故障發生時仍能夠繼續工做,這樣就將系統的停機時間減小到了最小。集羣系統在提升系統可靠性的同時,也大大減少了系統故障帶來的業務損失,目前幾乎100%的互聯網網站都要求7*24小時提供服務。
      5. 透明性
                多個獨立計算機組成的鬆耦合集羣系統構成一個虛擬服務器。用戶或客戶端程序訪問集羣系統時,就像訪問一臺高性能,高可用的服務器同樣,集羣中一部分服務器的上線,下線不會中斷整個系統服務,這對用戶也是透明的。
      6. 可管理性
                整個系統可能在物理上很大,但其實容易管理,就像管理一個單一映像系統同樣。在理想情況下,軟硬件模塊的插入能作到即插即用。
      7. 可編程性
                在集羣系統上,容易開發及修改各種應用程序。

1.3 集羣的常見分類

計算機集羣架構按功能和結構能夠分紅如下幾類:css

  • 負載均衡集羣,簡稱LBC或者LB
  • 高可用性集羣,簡稱HAC
  • 高性能計算集羣,簡稱HPC
  • 網格計算集羣

提示:
負載均衡集羣和高可用性集羣是互聯網行業經常使用的集羣架構模式,也是咱們要學習的重點。html

負載均衡集羣

  • 負載均衡集羣爲企業提供了更爲實用,性價比更高的系統架構解決方案。負載均衡集羣能夠把不少客戶集中的訪問請求負載壓力盡量平均地分攤在計算機集羣中處理。客戶訪問請求負載一般包括應用程序處理負載和網絡流量負載。這樣的系統很是適合使用同一組應用程序爲大量用戶提供服務的模式,每一個節點均可以承擔必定的訪問請求負載壓力,而且能夠實現訪問請求在各節點之間動態分配,以實現負載均衡。負載均衡集羣運行時,通常是經過一個或多個前端負載均衡器將客戶訪問請求分發到後端的一組服務器上,從而達到整個系統的高性能和高可用性。通常高可用性集羣和負載均衡集羣會使用相似的技術,或同時具備高可用性與負載均衡的特色。

負載均衡集羣的做用爲:前端

  • 分攤用戶訪問請求及數據流量(負載均衡)
  • 保持業務連續性,即7*24小時服務(高可用性)。
  • 應用於Web業務及數據庫從庫等服務器的業務

負載均衡集羣典型的開源軟件包括LVS,Nginx,Haproxy等。以下圖所示:java

提示:
不一樣的業務會有若干秒的切換時間,DB業務明顯長於Web業務切換時間。android

高可用性集羣

通常是指在集羣中任意一個節點失效的狀況下,該節點上的全部任務會自動轉移到其餘正常的節點上。此過程並不影響整個集羣的運行。nginx

  • 當集羣中的一個節點系統發生故障時,運行着的集羣服務會迅速做出反應,將該系統的服務分配到集羣中其餘正在工做的系統上運行。考慮到計算機硬件和軟件的容錯性,高可用性集羣的主要目的是使集羣的總體服務儘量可用。若是高可用性集羣中的主節點發生了故障,那麼這段時間內將由備節點代替它。備節點一般是主節點的鏡像。當它代替主節點時,它能夠徹底接管主節點(包括IP地址及其餘資源)提供服務,所以,使集羣系統環境對於用戶來講是一致的,既不會影響用戶的訪問。
  • 高可用性集羣使服務器系統的運行速度和響應速度會盡量的快。他們常常利用在多臺機器上運行的冗餘節點和服務來相互跟蹤。若是某個節點失敗,它的替補者將在幾秒鐘或更短期內接管它的職責。所以,對於用戶而言,集羣裏的任意一臺機器宕機,業務都不會受影響(理論狀況下)。

高可用性集羣的做用爲:git

  • 當一臺機器宕機時,另一臺機器接管宕機的機器的IP資源和服務資源,提供服務。
  • 經常使用於不易實現負載均衡的應用,好比負載均衡器,主數據庫,主存儲對之間。

高可用性集羣經常使用的開源軟件包括Keepalived,Heartbeat等,其架構圖以下圖所示:github

高性能計算集羣

  高性能計算集羣也稱並行計算。一般,高性能計算集羣涉及爲集羣開發的並行應用程序,以解決複雜的科學問題(天氣預報,石油勘探,核反應模擬等)。高性能計算集羣對外就好像一個超級計算機,這種超級計算機內部由數十至上萬個獨立服務器組成,而且在公共消息傳遞層上進行通訊以運行並行應用程序。在生產環境中實際就是把任務切成蛋糕,而後下發到集羣節點計算,計算後返回結果,而後繼續領新任務計算,如此往復。web

網格計算集羣 

  因爲不多用到,在此略

特別提示:
在互聯網網站運維中,比較經常使用的就是負載均衡集羣和高可用性集羣

1.4 經常使用的集羣軟硬件介紹及選型

企業運維中常見的集羣軟硬件產品

互聯網企業經常使用的開源集羣軟件有:Nginx,LVS,Haproxy,Keepalived,heartbeat。

互聯網企業經常使用的商業集羣硬件有:F5,Netscaler,Radware,A10等,工做模式至關於Haproxy的工做模式。

淘寶,趕集網,新浪等公司曾使用過Netscaler負載均衡產品。集羣硬件Netscaler的產品圖以下圖所示:

對於集羣軟硬件產品如何選型

下面是我對同窗們的基本選擇建議,更多的建議等你們學完負載均衡內容後再細分講解。

  • 當企業業務重要,技術力量又薄弱,而且但願出錢購買產品及獲取更好的服務時,能夠選擇硬件負載均衡產品,如F5,Netscaler,Radware等,此類公司多爲傳統的大型非互聯網企業,如銀行,證券,金融業及寶馬,奔馳公司等
  • 對於門戶網站來講,大多會並用軟件及硬件產品來分擔單一產品的風險,如淘寶,騰訊,新浪等。融資了的企業會購買硬件產品,如趕集等網站。
  • 中小型互聯網企業,因爲起步階段無利潤可賺或者利潤很低,會但願經過使用開源免費的方案來解決問題,所以會僱傭專門的運維人員進行維護。例如:51CTO等

相比較而言,商業的負載均衡產品成本高,性能好,更穩定,缺點是不能二次開發,開源的負載均衡軟件對運維人員的能力要求較高,若是運維及開發能力強,那麼開源的負載均衡軟件是不錯的選擇,目前的互聯網行業更傾向於使用開源的負載均衡軟件。

如何選擇開源集羣軟件產品

  • 中小企業互聯網公司網站在併發訪問和總訪問量不是很大的狀況下,建議首選Nginx負載均衡,理由是Nginx負載均衡配置簡單,使用方便,安全穩定,社區活躍,使用的人逐漸增多,成爲流行趨勢,另一個實現負載均衡的相似產品爲Haproxy(支持L4和L7負載,一樣優秀,但社區不如Nginx活躍)。
  • 若是要考慮Nginx負載均衡的高可用功能,建議首選Keepalived軟件,理由是安裝和配置簡單,使用方便,安全穩定,與Keepalived服務相似的高可用軟件還有Heartbeat(使用比較複雜,並不建議初學者使用)
  • 若是是大型企業互聯網公司,負載均衡產品可使用LVS+Keepalived在前端作四層轉發(通常是主備或主主,若是須要擴展可使用DNS或前端使用OSPF),後端使用Nginx或者Haproxy作7層轉發(能夠擴展到百臺),再後面是應用服務器,若是是數據庫與存儲的負載均衡和高可用,建議選擇LVS+Heartbeat,LVS支持TCP轉發且DR模式效率很高,Heartbeat能夠配合drbd,不但能夠進行VIP的切換,還能夠支持塊設備級別的數據同步(drbd),以及資源服務的管理。

1.5 Nginx負載均衡集羣介紹

搭建負載均衡服務的需求

負載均衡集羣提供了一種廉價,有效,透明的方法,來擴展網絡設備和服務器的負載,帶寬和吞吐量,同時增強了網絡數據處理能力,提升了網絡的靈活性和可用性。

搭建負載均衡服務的需求以下:

(1)把單臺計算機沒法承受的大規模併發訪問或數據流量分擔到多臺節點設備上,分別進行處理,減小用戶等待響應的時間,提高用戶體驗。
(2)單個重負載的運算分擔到多臺節點設備上作並行處理,每一個節點設備處理結束後,將結果彙總,返回給用戶,系統處理能力獲得大幅度提升。
(3)7*24小時的服務保證,任意一個或多個有限後面節點設備宕機,不能影響業務。

在負載均衡集羣中,同組集羣的全部計算機節點都應該提供相同的服務。集羣負載均衡器會截獲全部對該服務的入站請求。而後將這些請求儘量地平均地分配在全部集羣節點上。

Nginx負載均衡集羣介紹

  1. 反向代理與負載均衡概念簡介
    • 嚴格地說,Nginx僅僅是做爲Nginx Proxy反向代理使用的,由於這個反向代理功能表現的效果是負載均衡集羣的效果,因此本文稱之爲Nginx負載均衡。那麼,反向代理和負載均衡有什麼區別呢?
    • 普通負載均衡軟件,例如大名鼎鼎的LVS,其實功能只是對請求數據包的轉發(也可能會改寫數據包),傳遞,其中DR模式明顯的特徵是從負載均衡下面的節點服務器來看,接收到的請求仍是來自訪問負載均衡器的客戶端的真實用戶,而反向代理就不同了,反向代理接收訪問用戶的請求後,會代理用戶從新發起請求代理下的節點服務器,最後把數據返回給客戶端用戶,在節點服務器看來,訪問的節點服務器的客戶端用戶就是反向代理服務器了,而非真實的網站訪問用戶。
    • 一句話,LVS等的負載均衡是轉發用戶請求的數據包,而Nginx反向代理是接收用戶的請求而後從新發起請求去請求其後面的節點。
  2. 實現Nginx負載均衡的組件說明
    實現Nginx負載均衡的組件主要有兩個,以下表:

     

1.6 快速實踐Nginx負載均衡環境準備

本節先帶同窗們一塊兒操做實戰,讓同窗們對Nginx負載均衡有一個初步的概念,而後再繼續深刻講解Nginx負載均衡的核心知識應用。

上圖是快速實踐Nginx負載均衡的邏輯架構圖

在上圖中,全部用戶的請求統一發送到Nginx負載均衡器,而後由負載均衡器根據調度算法來請求Web01和Web02

軟硬件準備

  1. 硬件準備
    準備4臺VM虛擬機(有物理服務器更佳),兩臺作負載均衡,兩臺作RS,以下表:
    HOSTNAME IP 說明
    lb01 192.168.103.121 Nginx主負載均衡器
    lb02 192.168.103.122 Nginx副負載均衡器
    web01 192.168.103.123 Web01服務器
    web02 192.168.103.124 Web02服務器
  2. 軟件準備
    系統:CentOS6.5 x86_64
    軟件:nginx-1.10.2.tar.gz
    修改hostname方便查看:
    hostname lb01
    hostname lb02
    hostname web01
    hostname web02

二、安裝Nginx

2.一、安裝web服務器

安裝apache(不建議)(只是用來記錄操做)

在 web01 與 web02 上安裝 apache 

# 安裝apache
[root@web01 ~]# yum install httpd -y
[root@web01 init.d]# service httpd start
[root@web02 ~]# yum install httpd -y
[root@web02 init.d]# service httpd start

# 查看是否啓動
[root@web02 ~]# lsof -i :80
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   11393   root    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11394 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11395 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11396 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11397 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11409 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11410 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11411 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11412 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11413 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11414 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)

# 修改index.html頁內容
[root@web01 /]# echo 192.168.103.123 >/var/www/html/index.html
[root@web02 /]# echo 192.168.103.124 >/var/www/html/index.html

安裝nginx

下面將在以上4臺服務器上安裝Nginx,這裏只給出安裝的命令部分。

  1. 安裝上傳下載組件
    # 安裝上傳下載組件
    [root@lb01 /]# yum install lrzsz -y
    [root@lb02 /]# yum install lrzsz -y
    [root@web01 /]# yum install lrzsz -y
    [root@web02 /]# yum install lrzsz -y
  2. 安裝pcre與gcc環境依賴
    # 安裝pcre與gcc環境依賴
    # lb01
    [root@lb01 tools]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@lb01 tools]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@lb01 tools]# yum install gcc -y 
    # lb02
    [root@lb02 tools]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@lb02 tools]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@lb02 tools]# yum install gcc -y 
    # web01
    [root@web01 /]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@web01 /]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@web01 /]# yum install gcc -y 
    # web02
    [root@web02 /]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@web02 /]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@web02 /]# yum install gcc -y 
  3. 安裝Nginx
    # 上傳nginx文件
    [root@lb01 ~]# mkdir -p /home/oldboy/tools
    [root@lb01 ~]# cd /home/oldboy/tools
    [root@lb01 tools]# rz -y
    [root@lb01 tools]# tar xf nginx-1.6.2.tar.gz
    [root@lb01 tools]# cd nginx-1.6.2/
    # 建立nginx用戶
    [root@lb01 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx
    # 安裝編譯
    [root@lb01 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install
    # 創建ln連接
    [root@lb01 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
    # 啓動nginx
    [root@lb01 nginx-1.6.2]# nginx
    # 中止nginx
    # [root@lb01 nginx-1.6.2]# nginx -s stop
    # 查看
    # [root@lb01 nginx-1.6.2]# lsof -i :80
    
    # 上傳nginx文件
    [root@lb02 ~]# mkdir -p /home/oldboy/tools
    [root@lb02 ~]# cd /home/oldboy/tools
    [root@lb02 tools]# rz -y
    [root@lb02 tools]# tar xf nginx-1.6.2.tar.gz
    [root@lb02 tools]# cd nginx-1.6.2/
    # 建立nginx用戶
    [root@lb02 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx
    # 安裝編譯
    [root@lb02 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install
    # 創建ln連接
    [root@lb02 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
    # 啓動nginx
    [root@lb02 nginx-1.6.2]# nginx
    # 中止nginx
    # [root@lb02 nginx-1.6.2]# nginx -s stop
    # 查看
    # [root@lb02 nginx-1.6.2]# lsof -i :80

2.二、配置用於測試的Web服務

本小節將在兩臺NginxWeb服務器的節點上操做(web01與web02):配置並查看Web服務器的配置結果。

  1. 添加本地主機名(可選)
    // web01
    # 添加本地主機名
    [root@web01 /]# cd usr/local/nginx/conf/
    [root@web01 conf]# vim /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.103.123 www.yunjisuan.com
    192.168.103.123 bbs.yunjisuan.com
    
    // web02
    # 添加本地主機名
    [root@web02 /]# cd usr/local/nginx/conf/
    [root@web02 conf]# vim /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.103.124 www.yunjisuan.com
    192.168.103.124 bbs.yunjisuan.com
  2. 安裝  telnet 可選

    // web01
    # 添加本地主機名
    # 安裝telnet
    [root@web01 /]# yum install telnet nmap dos2unix -y
    
    // web02
    # 安裝telnet
    [root@web02 /]# yum install telnet nmap dos2unix -y
  3. 配置nginx

    // web01
    # 配置nginx
    [root@web01 nginx-1.6.2]# cd /usr/local/nginx/conf/
    # 刪除nginx.conf.default中的#|^$,並寫入nginx.conf
    [root@web01 conf]# egrep -v "#|^$" nginx.conf.default
    [root@web01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
    
    // web02
    # 安裝telnet
    [root@web02 nginx-1.6.2]# cd /usr/local/nginx/conf/
    # 刪除nginx.conf.default中的#|^$,並寫入nginx.conf
    [root@web02 conf]# egrep -v "#|^$" nginx.conf.default
    [root@web02 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
  4. 修改  nginx.conf 

    // web01
    [root@web01 conf]# vim nginx.conf
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server {
            listen       80;
            server_name  bbs.yunjisuan.com;
            location / {
                root   html/bbs;
                index  index.html index.htm;
            }
        }
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                root   html/www;
                index  index.html index.htm;
            }
        }
    }
    
    // web02
    [root@web02 conf]# vim nginx.conf
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server {
            listen       80;
            server_name  bbs.yunjisuan.com;
            location / {
                root   html/bbs;
                index  index.html index.htm;
            }
        }
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                root   html/www;
                index  index.html index.htm;
            }
        }
    }

    這裏故意將www虛擬主機放在下面,便於用後面的參數配置測試效果

  5. 檢查語法錯誤
    // web01
    [root@web01 conf]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
    
    // web02
    [root@web02 conf]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
  6. 從新加載nginx
    // web01
    [root@web01 conf]# nginx -s reload
    [root@web01 conf]# netstat -antup | grep nginx
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      17429/nginx: master 
    
    // web02
    [root@web02 conf]# nginx -s reload
    [root@web02 conf]# netstat -antup | grep nginx
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      17429/nginx: master 
  7. 填充測試文件數據
    // web01
    [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs}
    [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html
    [root@web01 /]# cat /usr/local/nginx/html/www/index.html
    192.168.103.123 192.168.122.1 www
    [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html
    [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html
    192.168.103.123 192.168.122.1 bbs
    
    // web02
    [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs}
    [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html
    [root@web01 /]# cat /usr/local/nginx/html/www/index.html
    192.168.103.124 192.168.122.1 www
    [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html
    [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html
    192.168.103.124 192.168.122.1 bbs
  8. 測試
    // web01
    [root@web01 /]# curl www.yunjisuan.com
    192.168.103.123 192.168.122.1 www
    [root@web01 /]# curl bbs.yunjisuan.com
    192.168.103.123 192.168.122.1 bbs
    
    
    // web02
    [root@web02 /]# curl www.yunjisuan.com
    192.168.103.124 192.168.122.1 www
    [root@web02 /]# curl bbs.yunjisuan.com
    192.168.103.124 192.168.122.1 bbs

2.三、實現一個簡單的負載均衡

配置文檔:http://nginx.org/en/docs/http/ngx_http_upstream_module.html

語法:

upstream backend {
    server backend1.example.com       weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

測試:(本操做基於lb01和lb02)

  1. 添加本地主機名(可選)
    添加本地域名
    [root@lb01 conf]# vim /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.103.121 www.yunjisuan.com
  2. 安裝 telnet (可選)

    # 安裝telnet
    [root@lb01 conf]# yum install telnet nmap dos2unix -y
  3. 配置nginx
    # 配置nginx
    [root@lb01 nginx-1.6.2]# cd /usr/local/nginx/conf/
    # 刪除nginx.conf.default中的#|^$,並寫入nginx.conf
    [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default
    [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
  4. 建立配置信息(notepad++中)
    upstream webpools {
        server 192.168.103.123       weight=5;
        server 192.168.103.124       weight=5;
    
        server 192.168.103.125  weight=5   backup;
    }
    
    server {
        location / {
            proxy_pass http://webpools;
        }
    }
  5. 修改 nginx.conf 
    [root@lb01 conf]# vim nginx.conf
    
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
    
        upstream webpools { server 192.168.103.123:80       weight=5;
            server 192.168.103.124:80       weight=5;
    
            server 192.168.103.125:80  weight=5 backup; }
    
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                root   html;
                index  index.html index.htm;
     proxy_pass http://webpools;
            }
        }
    }

    注意:upstream名稱不能包含下劃線,不然會報以下錯誤

    <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
    <html><head>
    <title>400 Bad Request</title>
    </head><body>
    <h1>Bad Request</h1>
    <p>Your browser sent a request that this server could not understand.<br />
    </p>
    <p>Additionally, a 400 Bad Request
    error was encountered while trying to use an ErrorDocument to handle the request.</p>
    </body></html>
    View Code
  6. 檢查語法錯誤
    [root@lb01 conf]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
  7. 從新加載nginx
    [root@lb01 conf]# nginx -s reload
  8. 測試

     

    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.123 192.168.122.1 bbs
    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.124 192.168.122.1 bbs
    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.123 192.168.122.1 bbs
    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.124 192.168.122.1 bbs

     

三、Nginx負載均衡核心組件介紹

3.0、Nginx主配置文件nginx.conf

  Nginx主配置文件nginx.conf是一個純文本類型的文件(其餘配置文件大多也是如此),它位於Nginx安裝目錄下的conf目錄,整個配置文件是以區塊的形式組織的。通常,每一個區塊以一個大括號「{}」來表示,區塊能夠分爲幾個層次,整個配置文件中Main區位於最上層,在Main區下面能夠有Events區,HTTP區等層級,在HTTP區中又包含有一個或多個Server區,每一個Server區中又可有一個或多個location區,整個Nginx配置文件nginx.conf的主體框架爲:

[root@chensiqi conf]# egrep -v "#|^$" nginx.conf #去掉包含#號和空行的內容
worker_processes  1; #worker進程的數量
error_log  logs/error.log;  #錯誤日誌(默認沒開)
pid        logs/nginx.pid;  #進程號(默認沒開)
events {    #事件區塊開始
    worker_connections  1024;   #每一個worker進程支持的最大鏈接數
}           #事件區塊結束
http {      #http區塊開始
    include       mime.types;   #Nginx支持的媒體類型庫文件包含
    default_type  application/octet-stream; #默認的媒體類型
    sendfile        on;     #開啓高效傳輸模式
    keepalive_timeout  65;  #鏈接超時。
    server {      #網站配置區域(第一個server第一個虛擬主機站點)
        listen       80;    #提供服務的端口,默認80
        server_name  www.chensiqi.org; #提供服務的域名主機名
        location / {    #第一個Location區塊開始
            root   html;  #站點的根目錄(相對於nginx安裝路徑)
            index  index.html index.htm; #默認的首頁文件,多個用空格分開
        }
        error_page 500 502 503 504  /50x.html;  #出現對應的http狀態碼時,使用50x.html迴應客戶
        location = /50x.html {  #Location區塊開始,訪問50x.html
            root   html;     #指定對應的站點目錄爲html
        }
    }
    server {      #網站配置區域(第二個server第二個虛擬主機站點)
        listen       80;    #提供服務的端口,默認80
        server_name  bbs.chensiqi.org; #提供服務的域名主機名
        location / {    #服務區塊
            root   html;  #相對路徑(nginx安裝路徑)
            index  index.html index.htm;
        }
        location = /50x.html { #發生錯誤訪問的頁面
            root   html;
        }
    }
}

整個nginx配置文件的核心框架以下:

worker_processes 1;
events {
    
    worker_connections 1024;

}
http {
    include mime.types;
    server {
        listen  80;
        server_name localhost;
        location / {
            root  html;
            index  index.html index.htm;
        }
    }
}

Nginx其餘配置文件

  • 若是是配合動態服務(例如PHP服務),Nginx軟件還會用到擴展的fastcgi相關配置文件,這個配置是經過在Nginx.conf主配置文件中嵌入include命令來實現的,不過默認狀況是註釋狀態,不會生效。

  • fastcgi.conf配置文件的初始內容以下:

    [root@localhost conf]# cat fastcgi.conf
    
    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param  QUERY_STRING       $query_string;
    fastcgi_param  REQUEST_METHOD     $request_method;
    fastcgi_param  CONTENT_TYPE       $content_type;
    fastcgi_param  CONTENT_LENGTH     $content_length;
    
    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  REQUEST_URI        $request_uri;
    fastcgi_param  DOCUMENT_URI       $document_uri;
    fastcgi_param  DOCUMENT_ROOT      $document_root;
    fastcgi_param  SERVER_PROTOCOL    $server_protocol;
    fastcgi_param  REQUEST_SCHEME     $scheme;
    fastcgi_param  HTTPS              $https if_not_empty;
    
    fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
    
    fastcgi_param  REMOTE_ADDR        $remote_addr;
    fastcgi_param  REMOTE_PORT        $remote_port;
    fastcgi_param  SERVER_ADDR        $server_addr;
    fastcgi_param  SERVER_PORT        $server_port;
    fastcgi_param  SERVER_NAME        $server_name;
    
    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param  REDIRECT_STATUS    200;
  • fastcgi_params 默認配置文件的內容以下:
    [root@localhost conf]# cat fastcgi_params
    
    fastcgi_param  QUERY_STRING       $query_string;
    fastcgi_param  REQUEST_METHOD     $request_method;
    fastcgi_param  CONTENT_TYPE       $content_type;
    fastcgi_param  CONTENT_LENGTH     $content_length;
    
    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  REQUEST_URI        $request_uri;
    fastcgi_param  DOCUMENT_URI       $document_uri;
    fastcgi_param  DOCUMENT_ROOT      $document_root;
    fastcgi_param  SERVER_PROTOCOL    $server_protocol;
    fastcgi_param  REQUEST_SCHEME     $scheme;
    fastcgi_param  HTTPS              $https if_not_empty;
    
    fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
    
    fastcgi_param  REMOTE_ADDR        $remote_addr;
    fastcgi_param  REMOTE_PORT        $remote_port;
    fastcgi_param  SERVER_ADDR        $server_addr;
    fastcgi_param  SERVER_PORT        $server_port;
    fastcgi_param  SERVER_NAME        $server_name;
    
    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param  REDIRECT_STATUS    200;

    上述未作註釋的目錄或文件是比較少用的,有關動態擴展配置後文講到PHP服務時再來說解。

Nginx的功能模塊說明

增長錯誤日誌

error_log file level;

常見的日誌級別【debug|info|notice|warn|error|crit|alert|emerg】
生產場景通常是warn|error|crit這三個級別之一,注意不要配置info等較低級別,會帶來巨大磁盤I/O消耗。
error_log的默認值爲:
# default:error_log logs/error.log error;

worker_processes  1;
error_log logs/error.log;    #很是簡單,通常增長此行便可
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include extra/www.conf;
    include extra/mail.conf;
    include extra/status.conf;

}

Nginx訪問日誌輪詢切割

默認狀況下Nginx會把全部的訪問日誌生成到一個指定的訪問日誌文件access.log裏,但這樣一來,時間長了就會致使日誌個頭很大,不利於日誌的分析和處理,所以,有必要對Nginx日誌,按天或按小時進行切割,使其分紅不一樣的文件保存。

[root@localhost nginx]# cat /server/scripts/cut_nginx_log.sh 
#!/bin/bash
#日誌切割腳本可掛定時任務,天天00點整執行

Dateformat=`date +%Y%m%d`
Basedir="/usr/local/nginx"
Nginxlogdir="$Basedir/logs"
Logname="access"

[ -d $Nginxlogdir ] && cd $Nginxlogdir || exit 1
[ -f ${Logname}.log ] || exit 1
/bin/mv ${Logname}.log ${Dateformat}_${Logname}.log
$Basedir/sbin/nginx -s reload

[root@localhost nginx]# cat >>/var/spool/cron/root << KOF
#cut nginx access log by Mr.chen
00 00 * * * /bin/bash /server/scripts/cut_nginx_log.sh >/dev/null 2>&1

Nginx location

語法爲:

location [ = | ~ | ~* | ^~ ] uri {

  ...

}

上圖是對location語法的說明。上述語法中的URI部分是關鍵,這個URI能夠是普通的字符串地址路徑,或者是正則表達式,匹配成功則執行後面大括號裏的相關命令。正則表達式的前面還能夠有「~」或「~*」等特殊字符。

 

 

匹配這兩種特殊字符「~」或「~*」的區別爲:「~」用於區分大小寫(大小寫敏感)的匹配;「~*」用於不區分大小寫的匹配。還能夠用邏輯操做符「!」對上面的匹配取反,即「!~」和「!~*」。此外,「^~」的做用是先進行字符串的前綴匹配(必須之後邊的字符串開頭),若是能匹配到,就再也不進行其餘location的正則匹配了。

location匹配示例

[root@localhost nginx]# cat /usr/local/nginx/conf/extra/www.conf 
    server {
        listen       80;
        server_name  www.yunjisuan.com;
       root    /var/www/html/wwwcom;
        location / {
          return 401;     
        }
       location = / {
          return 402;
       }
       location = /images/ {
          return 501;
       }
       location /documents/ {
          return 403;
       }
       location ^~ /images/ {
          return 404;
       }
       location ~* \.(gif|jpg|jpeg)$ {
          return 500;
       }
    }

匹配結果

[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com
402        #匹配了=的狀況
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/
402         #匹配了=的狀況
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/xxxx
401         #匹配不到默認匹配 /的狀況
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/
403         #匹配字符串
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/
501         #優先匹配=的狀況
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/1.jpg
404         #匹配
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/images/1.jpg
500         #匹配~*的狀況

從多個location的配置匹配能夠看出匹配的優先順序

順序 匹配標識的location 匹配說明
1 " location = / { " 精確匹配
2 " location ^~ /images/ { " 先進行字符串的前綴匹配,若是匹配到就不作正則匹配檢查
3 " loction ~* \.(gif | jpg | jpeg)$ { " 正則匹配,*爲不區分大小寫
4 " location /documents/ { " 匹配常規字符串,模糊匹配,若是有正則檢查,正則優先
5 " location / { " 全部location都不能匹配後的默認匹配原則

Nginx rewrite

和Apache等Web服務軟件同樣,Nginx rewrite的主要功能也是實現URL地址重寫。Nginx的rewrite規則須要PCRE軟件的支持,即經過Perl兼容正則表達式語法進行規則匹配。默認參數編譯時,Nginx就會安裝支持rewrite的模塊,可是,也必需要有PCRE軟件的支持。

  • rewrite指令語法
    指令語法:rewrite regex replacement 【flag】;
    默認值:none
    應用位置:server,location,if
    rewrite是實現URL重寫的關鍵指令,根據regex(正則表達式)部分的內容,重定向到replacement部分,結尾是flag標記。下面是一個簡單的URL rewrite跳轉例子:
    rewrite ^/(.*) http://www.baidu.com/$1  permanent;

    在上述指令中,rewrite爲固定關鍵字,表示開啓一條rewrite匹配規則,regex部分是^(.*),這是一個正則表達式,表示匹配全部,匹配成功後跳轉到http://www.baidu.com/$1 。這裏的$1是取前面regex部分括號裏的內容,結尾的permanent;是永久301重定向標記,即跳轉到後面的http://www.baidu.com/$1 地址上。

  • regex經常使用正則表達式說明
  • rewrite指令的最後一項參數flag標記的說明



在以上的flag標記中,last和break用來實現URL重寫,瀏覽器地址欄的URL地址不變,但在服務器端訪問的程序及路徑發生了變化。redirect和permanent用來實現URL跳轉,瀏覽器地址欄會顯示跳轉後的URL地址。

last和break標記的實現功能相似,但兩者之間有細微的差異,使用alias指令時必須用last標記,使用proxy_pass指令時要使用break標記。last標記在本條rewrite規則執行完畢後,會對其所在的server{...}標籤從新發起請求,而break標記則會在本條規則匹配完成後,終止匹配,再也不匹配後面的規則。

Nginx rewrite 的企業應用場景

  • 能夠調整用戶瀏覽的URL,使其看起來更規範,合乎開發及產品人員的需求。
  • 爲了讓搜索引擎收錄網站內容,並讓用戶體驗更好,企業會將動態URL地址假裝成靜態地址提供服務
  • 網站換新域名後,讓舊域名的訪問跳轉到新的域名上,例如:讓京東的360buy換成了jd.com
  • 根據特殊變量,目錄,客戶端的信息進行URL跳轉等。

Nginx rewrite 301 跳轉

以往咱們是經過別名方式實現yunjisuan.com和www.yunjisuan.com訪問同一個地址的,事實上,除了這個方式外,還可使用nginx rewrite 301 跳轉的方式來實現。實現的配置以下:

[root@localhost nginx]# cat conf/extra/www.conf 
#www virtualhost by Mr.chen   
    server {
        listen       80;
        server_name  www.yunjisuan.com;
       root    /var/www/html/wwwcom;
        location / {
        index index.html index.htm;
        }
#   location = / {
#       return 402;
#   }
    location = /images/ {
        return 501;
    }
    location /documents/ {
        return 403;
    }
    location ^~ /images/ {
        return 404;
    }
    location ~* \.(gif|jpg|jpeg)$ {
        return 500;
    }
    
    }

    server{
        listen  80;
        server_name yunjisuan.com;
 rewrite ^/(.*)  http://www.yunjisuan.com/$1 permanent;
        #當用戶訪問yunjisuan.com及下面的任意內容時,都會經過這條rewrite跳轉到www.yunjisuan.com對應的地址
    }

 

3.一、Nginx upstream模塊

upstream模塊介紹

  • Nginx的負載均衡功能依賴於 ngx_http_upsteam_module 模塊,所支持的代理方式包括 proxy_passfastcgi_passuwsgi_passscgi_passmemcached_pass, and grpc_pass directives.等,新版Nginx軟件支持的方式有所增長。本文主要講解proxy_pass代理方式。
  • ngx_http_upstream_module模塊容許Nginx定義一組或多組節點服務器組,使用時能夠經過proxy_pass代理方式把網站的請求發送到事先定義好的對應Upstream組的名字上,具體寫法爲「proxy_pass http:// www_server_pools」,其中www_server_pools就是一個Upstream節點服務器組名字。
  • ngx_http_upstream_module模塊官方地址爲:http://nginx.org/en/docs/http/ngx_http_upstream_module.html

upstream模塊語法

upstream模塊的語法至關簡單,這裏直接上範例給同窗們講。

範例1:基本的upstream配置案例

upstream www_server_pools {

    # upstream是關鍵字必須有,後面的www_server_pools爲一個Upstream集羣組的名字,能夠本身起名,調用時就用這個名字
    server 192.168.103.123:80 weight=5;
    server 192.168.103.124:80 weight=10;
    server 192.168.103.125:80 weight=15;    
#server關鍵字是固定的,後面能夠接域名(門戶會用)或IP。若是不指定端口,默認是80端口。weight表明權重,數值越大被分配的請求越多,結尾有分號,別忘了 }

範例2:較完整的upstream配置案例

upstream blog_server_pool {

    server 192.168.103.123;   #這行標籤和下行是等價的
    server 192.168.103.124:80 weight=1 max_fails=1 fail_timeout=10s;       #這行標籤和上一行是等價的,此行多餘的部分就是默認配置,不寫也能夠。

    server 192.168.103.125:80 weight=1 max_fails=2 fail_timeout=20s backup;

    #   server最後面能夠加不少參數,具體參數做用看下文的表格

}

範例3:使用域名及socket的upstream配置案例

upstream backend {

    server backend1.example.com weight=5;
    server backend2.example.com:8080;   #域名加端口。轉發到後端的指定端口上
    server unix:/tmp/backend3;  #指定socket文件

    #提示:server後面若是接域名,須要內網有DNS服務器或者在負載均衡器的hosts文件作域名解析。

    server 192.168.103.123;
    server 192.168.103.124:8080;
    server backup1.example.com:8080 backup;

    #備份服務器,等上面指定的服務器都不可訪問的時候會啓動,backup的用法和Haproxy中用法同樣

    server backup2.example.com:8080 backup;

}

若是是兩臺Web服務器作高可用,常規方案就須要keepalived配合,那麼這裏使用Nginx的backup參數經過負載均衡功能就能夠實現Web服務器集羣了,對於企業應用來講,能作集羣就不作高可用。

upstream模塊相關說明

upstream模塊的內容應放於nginx.conf配置的http{}標籤內,其默認調度節點算法是wrr(weighted round-robin,即權重輪詢)

下圖爲upstream模塊內部server標籤部分參數說明

提示:
以上參數與專業的Haproxy參數很相似,但不如Haproxy的參數易懂。

來看個示例,以下:

upstream backend {

server backend1.example.com weight=5; #若是就是單個Server,不必設置權重
server 127.0.0.1:8080 max_fail=5 fail_timeout=10s;
#當檢測次數等於5的時候,5次連續檢測失敗後,間隔10s再從新檢測。
server unix:/tmp/backend3;
server backup1.example.com:8080 backup; #熱備機器設置

}

須要特別說明的是,若是是Nginx代理Cache服務,可能須要使用hash算法,此時若宕機,可經過設置down參數確保客戶端用戶按照當前的hash算法訪問,這一點很重要。示例配置以下:

upstream backend {

ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;

}

注意:ip_hash不能與backup共同使用

下面是Haproxy負載均衡器server標籤的配置示例。

#開啓對後端服務器的健康檢測,經過GET /test/index.php來判斷後端服務器的健康狀況
server php_server_1 192.168.103.123:80 cookie 1 check inter 2000 rise 3 fall 3 weight 2
server php_server_2 192.168.103.124:80 cookie 2 check inter 2000 rise 3 fall 3 weight 1
server php_server_bak 192.168.103.125:80 cookie 3 check inter 1500 rise 3 fall 3 backup

上述命令的說明以下:

  • weight:調節服務器的請求分配權重。
  • check:開啓對該服務器健康檢查。
  • inter:設置連續兩次的健康檢查間隔時間,單位毫秒,默認值2000
  • rise:指定多少次連續成功的健康檢查後,便可認定該服務器處於可用狀態。
  • fall:指定多少次不成功的健康檢查後,即認爲服務器爲宕機狀態,默認值3.
  • maxconn:指定可被髮送到該服務器的最大併發鏈接數。

upstream模塊調度算法

調度算法通常分爲兩類:

  • 第一類爲靜態調度算法,即負載均衡器根據自身設定的規則進行分配,不須要考慮後端節點服務器的狀況,例如:rr,wrr,ip_hash等都屬於靜態調度算法。
  • 第二類爲動態調度算法,即負載均衡器會根據後端節點的當前狀態來決定是否分發請求,例如:鏈接數少的優先得到請求,響應時間短的優先得到請求。例如:least_conn,fair等都屬於動態調度算法。

下面介紹一下常見的調度算法

  • rr輪詢(默認調度算法,靜態調度算法)
      按客戶端請求順序把客戶端的請求逐一分配到不一樣的後端節點服務器,這至關於LVS中的rr算法,若是後端節點服務器宕機(默認狀況下Nginx只檢測80端口),宕機的服務器會被自動從節點服務器池中剔除,以使客戶端的用戶訪問不受影響。新的請求會分配給正常的服務器。
  • wrr(權重輪詢,靜態調度算法)
      在rr輪詢算法的基礎上加上權重,即爲權重輪詢算法,當使用該算法時,權重和用戶訪問成正比,權重值越大,被轉發的請求也就越多。能夠根據服務器的配置和性能指定權重值大小,有效解決新舊服務器性能不均帶來的請求分配問題。
  • ip_hash(靜態調度算法)(會話保持)
      每一個請求按客戶端IP的hash結果分配,當新的請求到達時,先將其客戶端IP經過哈希算法哈希出一個值,在隨後的客戶端請求中,客戶IP的哈希值只要相同,就會被分配至同一臺服務器,該調度算法能夠解決動態網頁的session共享問題,但有時會致使請求分配不均,即沒法保證1:1的負載均衡,由於在國內大多數公司都是NAT上網模式,多個客戶端會對應一個外部IP,因此,這些客戶端都會被分配到同一節點服務器,從而致使請求分配不均。LVS負載均衡的-p參數,Keepalived配置裏的persistence_timeout 50參數都相似這個Nginx裏的ip_hash參數,其功能均可以解決動態網頁的session共享問題。
    咱們來看一個示例,以下:
    upstream yunjisuan_lb{
    
        ip_hash;
        server 192.168.0.223:80;
        server 192.168.0.224:8080;
    
    }
    
    upstream backend{
    
        ip_hash;
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com down;
        server backend4.example.com;
    
    }

    注意:
    當負載調度算法爲ip_hash時,後端服務器在負載均衡調度中的狀態不能有weight和backup,即便有也不會生效。

  • fair(動態調度算法)
            此算法會根據後端節點服務器的響應時間來分配請求,響應時間短的優先分配。這是更加智能的調度算法。此種算法能夠根據頁面大小和加載時間長短智能地進行負載均衡,也就是根據後端服務器的響應時間來分配請求,響應時間短的優先分配。Nginx自己不支持fair調度算法,若是須要使用這種調度算法,必須下載Nginx相關模塊upstream_fair
    示例以下:
    upstream yunjisuan_lb{
    
        server 192.168.103.123;
        server 192.168.103.124;
        fair;
    
    }
  • least_conn
          least_conn算法會根據後端節點的鏈接數來決定分配狀況,哪一個機器鏈接數少就分發。
    除了上面介紹的這些算法外,還有一些第三方調度算法,例如:url_hash,一致性hash算法等,介紹以下。
  • url_hash算法(web緩存節點)
      與ip_hash相似,這裏是根據訪問URL的hash結果來分配請求的,讓每一個URL定向到同一個後端服務器,後端服務器爲緩存服務器時效果顯著。在upstream中加入hash語句,server語句中不能寫入weight等其餘的參數,hash_method使用的是hash算法。url_hash按訪問URL的hash結果來分配請求,使每一個URL定向到同一個後端服務器,能夠進一步提升後端緩存服務器的效率命令率。Nginx自己是不支持url_hash的,若是須要使用這種調度算法,必須安裝Nginx的hash模塊軟件包
    url_hash(web緩存節點)和ip_hash(會話保持)相似。示例配置以下:
    upstream yunjisuan_lb {
    
        server squid1:3128;
        server squid2:3128;
        hash $request_uri;
        hash_method crc32;
    
    }
  • 一致性hash算法
      一致性hash算法通常用於代理後端業務爲緩存服務(如Squid,Memcached)的場景,經過將用戶請求的URI或者指定字符串進行計算,而後調度到後端的服務器上,此後任何用戶查找同一個URI或者指定字符串都會被調度到這一臺服務器上,所以後端的每一個節點緩存的內容都是不一樣的,一致性hash算法能夠解決後端某個或幾個節點宕機後,緩存的數據動盪最小,一致性hash算法知識比較複雜,詳細內容能夠參考百度上的相關資料,這裏僅僅給出配置示例:
    http {
        upstream test {
    
            consistent_hash $request_uri;
            server 127.0.0.1:9001 id=1001 weight=3;
            server 127.0.0.1:9002 id=1002 weight=10;
            server 127.0.0.1:9003 id=1003 weight=20;
    
        }
    }

    雖然Nginx自己不支持一致性hash算法,但Nginx得分支Tengine支持。詳細可參考http://tengine.taobao.org/document_cn/http_upstream_consistent_hash_cn.html

3.二、http_proxy_module模塊

proxy_pass指令介紹

  proxy_pass指令屬於 ngx_http_proxy_module 模塊,此模塊能夠將請求轉發到另外一臺服務器,在實際的反向代理工做中,會經過location功能匹配指定的URI,而後把接收到的符合匹配URI的請求經過proxy_pass拋給定義好的upstream節點池。該指令官方地址1見:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

下面proxy_pass的使用案例:

  • 將匹配URI爲name的請求拋給http://127.0.0.1/remote/.
    location /name/ {
    
        proxy_pass http://127.0.0.1/remote/;
    
    }
  • 將匹配URI爲some/path的請求拋給http://127.0.0.1
    location /some/path/ {
    
        proxy_pass http://127.0.0.1;
    
    }
  • 將匹配URI爲name的請求應用指定的rewrite規則,而後拋給http://127.0.0.1
    location /name/ {
    
        rewrite /name/( [^/]+ )  /username=$1 break;
        proxy_pass http://127.0.0.1;
    
    }

http proxy模塊參數

Nginx的代理功能是經過http proxy模塊來實現的。默認在安裝Nginx時已經安裝了http proxy模塊,所以可直接使用http proxy模塊。下面詳細解釋模塊1中每一個選項表明的含義,見下表:

3.2.一、Nginx負載均衡配置實戰(上接2.3節)

主機名 IP地址 角色說明
lb01 192.168.103.121 nginx主負載均衡
lb02 192.168.103.122 nginx從負載均衡
Web01 192.168.103.123 nginx web01服務器
Web02 192.168.103.124 nginx web02服務器

 

查看lb01的配置文件以下:

// lb01
[root@lb01 /]# cat /usr/local/nginx/conf/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    
    upstream webpools {
        #默認調度算法wrr,即權重輪詢算法
        #雖然定義的www服務器池可是這個服務器池也能夠做爲BBS等業務的服務器池。由於節點服務器的虛擬主機都是根據訪問的主機頭字段區分的。
        
        #若是就是單個Server,不必設置權重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #熱備機器設置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
        proxy_pass http://webpools; #經過proxy_pass功能把用過戶的請求交給上面反向代理upstream定義的webpools服務器池處理。
        }
    }
}

如今配置hosts解析到代理服務器lb01上,從新加載服務,訪問測試

[root@lb01 /]# tail -2 /etc/hosts
192.168.103.121 www.yunjisuan.com
192.168.103.121 bbs.yunjisuan.com
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
[root@lb01 /]# tail -2 /etc/hosts
192.168.103.121 www.yunjisuan.com
192.168.103.121 bbs.yunjisuan.com
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
[root@lb01 /]# curl www.yunjisuan.com
192.168.103.123 192.168.122.1 bbs
[root@lb01 /]# curl www.yunjisuan.com
192.168.103.124 192.168.122.1 bbs

從測試結果能夠看出,已經實現了反向代理,負載均衡功能,可是有一個特殊問題,出來的結果並非帶有www的字符串,而是bbs的字符串,根據訪問結果,咱們推測是訪問了Web節點下bbs的虛擬主機,明明代理的是www虛擬主機,爲何結果是訪問了後端的bbs虛擬主機了呢?問題又該如何解決?請同窗們繼續往下看。

反向代理多虛擬主機節點服務器企業案例

上一節代理的結果不對,究其緣由是當用戶訪問域名時確實是攜帶了www.yunjisuan.com主機頭請求Nginx反向代理服務器,可是反向代理向下面節點從新發起請求時,默認並無在請求頭裏告訴節點服務器要找哪臺虛擬主機,因此,Web節點服務器接收到請求後發現沒有主機頭信息,所以,就把節點服務器的第一個虛擬主機發給了反向代理了(節點上第一個虛擬主機放置的是故意這樣放置的bbs)。解決這個問題的方法,就是當反向代理向後從新發起請求時,要攜帶主機頭信息,以明確告訴節點服務器要找哪一個虛擬主機。具體的配置很簡單,就是在Nginx代理www服務虛擬主機配置裏增長以下一行配置便可:

proxy_set_header host $host;

在代理向後端服務器發送的http請求頭中加入host字段信息後,若後端服務器配置有多個虛擬主機,它就能夠識別代理的是哪一個虛擬主機。這是節點服務器多虛擬主機時的關鍵配置。整個Nginx代理配置爲:

// lb01
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream webpools {
        #若是就是單個Server,不必設置權重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #熱備機器設置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://webpools;
            proxy_set_header host $host;    #在代理向後端服務器發送的http請求頭中加入host字段信息,用於當後端服務器配置有多個虛擬主機時,能夠識別代理的是哪一個虛擬主機。這是節點服務器多虛擬主機時的關鍵配置。
        }
    }
}

此時,再從新加載Nginx服務,並用curl測試檢查,結果以下:

[root@lb01 /]# curl www.yunjisuan.com
192.168.103.123 192.168.122.1 www
[root@lb01 /]# curl www.yunjisuan.com
192.168.103.124 192.168.122.1 www
[root@lb01 /]# curl bbs.yunjisuan.com
192.168.103.123 192.168.122.1 bbs
[root@lb01 /]# curl bbs.yunjisuan.com
192.168.103.124 192.168.122.1 bbs

能夠看到此次訪問的結果和訪問的域名就徹底對應上了,這樣代理多虛擬主機的節點服務器就不會出問題了

通過反向代理後的節點服務器記錄用戶IP企業案例

修改 nginx.config 記錄日誌

// web01
[root@web01 conf]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}


// web02
[root@web02 conf]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}

完成了反向代理WWW服務後,天然很開心,可是,不久後你用其餘客戶端做爲客戶端測試時,就會發現一個問題,節點服務器對應的WWW虛擬主機的訪問日誌的第一個字段記錄的並非客戶端的IP,而是反向代理服務器的IP,最後一個字段也是「-」!

例如:使用任意windows客戶端計算機( 192.168.103.204 ),訪問已經解析好代理IP的www.yunjisuan.com後,去節點服務器www服務日誌查看,就會發現以下日誌:

[root@web02 logs]# tail -2 /usr/local/nginx/logs/access_www.log
192.168.103.121--[29/Aug/2019:17:29:23 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-"
192.168.103.121--[29/Aug/2019:17:29:33 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-"

Web01節點服務器對應的WWW虛擬主機的訪問日誌的第一個字段記錄的並非客戶端的IP而是反向代理服務器自己的IP(192.168.103.121),最後一個字段也是一個「-」,那麼如何解決這個問題?其實很簡單,一樣是增長以下一行參數:

proxy_set_header X-Forwarded-For $remote_addr;
#這是反向代理時,節點服務器獲取用戶真實IP的必要功能配置

解決上述問題的整個Nginx代理配置爲:

//lb01
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream webpools {
        #若是就是單個Server,不必設置權重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #熱備機器設置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://webpools;
            proxy_set_header host $host;    #在代理向後端服務器發送的http請求頭中加入host字段信息,用於當後端服務器配置有多個虛擬主機時,能夠識別代理的是哪一個虛擬主機。這是節點服務器多虛擬主機時的關鍵配置。
            proxy_set_header X-Forwarded-For $remote_addr; #在代理向後端服務器發送的http請求頭中加入X-Forwarded-For字段信息,用於後端服務器程序,日誌等接收記錄真實用戶的IP,而不是代理服務器的IP
        }
    }
}

從新加載Nginx反向代理服務:

[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload

特別注意,雖然反向代理已經配好了,可是節點服務器須要的訪問日誌若是要記錄用戶的真實IP,還必須進行日誌格式配置,這樣才能把代理傳過來的X-Forwarded-For頭信息記錄下來,具體配置爲:

// web01
[root@web01 /]# vim usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    #就是這裏的「$http_x_forwarded_for」參數,若是但願在第一行顯示,能夠替換掉第一行的$remote_addr變量。
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}



// web02
[root@web02 /]# vim usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    #就是這裏的「$http_x_forwarded_for」參數,若是但願在第一行顯示,能夠替換掉第一行的$remote_addr變量。
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}
View Code

完成Web01,Web02節點服務器的日誌配置後,就能夠檢查了,注意,不要用curl從反向代理上檢查,最好換一個客戶端檢查,這樣才能看到效果。這裏使用Windows客戶端計算機(IP爲192.168.103.204)訪問已經解析好代理IP的www.yunjisuan.com,以下圖所示:

// web01
[root@web01 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 
192.168.103.121--[29/Aug/2019:18:02:38 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"
192.168.103.121--[29/Aug/2019:18:02:42 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"



// web02
[root@web02 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 
192.168.103.121--[29/Aug/2019:18:02:41 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"
192.168.103.121--[29/Aug/2019:18:02:44 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"

其中,日誌裏的192.168.103.121爲反向代理的IP,對應Nginx日誌格式裏的$remote_addr變量,而日誌結尾的192.168.103.204對應的時日誌格式裏的「$http_x_forwarded_for」變量,即接收了前面反向代理配置中「proxy_set_header X-Forwarded-For $remote_addr;」參數X-Forwarded-For的IP了。
關於X-Forwarded-For的詳細說明,可見http://en.wikipedia.org/wiki/X-Forwwawrded-For。下圖是反向代理相關重要基礎參數的總結,供同窗們參考。

 

 

與反向代理配置相關的更多參數說明

除了具備多虛擬主機代理以及節點服務器記錄真實用戶IP的功能外,Nginx軟件還提供了至關多的做爲反向代理和後端節點服務器對話的相關控制參數,具體見前面在講解proxy模塊時提供的圖表。

相信同窗們對這些參數有了必定了解了,因爲參數衆多,最好把這些參數放到一個配置文件裏,而後用include方式包含到虛擬主機配置裏,效果以下:

//lb01
# 建立配置文件
[root@lb01 /]# vim /usr/local/nginx/conf/proxy.conf

proxy_set_header host $host;
proxy_set_header x-forwarded-for $remote_addr;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;

#修改配置
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream webpools {
        #若是就是單個Server,不必設置權重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #當檢測次數等於1的時候,1次連續檢測失敗後,間隔60s再從新檢測。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #熱備機器設置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://webpools;
 include proxy.conf;
        }
    }
}

# 從新加載
[root@lb01 /]# nginx -s reload

更多Nginx反向代理參數說明
http://nginx.org/en/docs/http/ngx_http_proxy_module.html

四、根據URL中的目錄地址實現代理轉發

案例背景:

經過Nginx實現動靜分離,即經過Nginx反向代理配置規則實現讓動態資源和靜態資源及其餘業務分別由不一樣的服務器解析,以解決網站性能,安全,用戶體驗等重要問題。

下圖爲企業常見的動靜分離集羣架構圖,此架構圖適合網站前端只使用同一個域名提供服務的場景,例如,用戶訪問的域名是www.yunjisuan.com,而後,當用戶請求www.yunjisuan.com/upload/xx地址時候,代理會分配請求到上傳服務器池處理數據;當用戶請求www.yunjisuan.com/static/xx地址的時候,代理會分配請求到靜態服務器池請求數據;當用戶請求www.yunjisuan.com/xx地址的時候,即不包含上述指定的目錄地址路徑時,代理會分配請求到默認的動態服務器池請求數據(注意:上面的xx表示任意路徑)。

4.一、準備:案例配置實戰

先進行企業案例需求梳理:

  • 當用戶請求www.yunjisuan.com/upload/xx地址時,實現由upload上傳服務器池處理請求。
  • 當用戶請求www.yunjisuan.com/static/xx地址時,實現由靜態服務器池處理請求。
  • 除此之外,對於其餘訪問請求,全都由默認的動態服務器池處理請求。

瞭解了需求後,就能夠進行upstream模塊服務器池的配置了。

//lb01
#static_pools爲靜態服務器池,有一個服務器,地址爲192.168.103.123,端口爲80.
upstream staticpools {
    server 192.168.103.123:80 weght=1;
}

#upload_pools爲上傳服務器池,有一個服務器地址爲192.168.103.124,端口爲80.
upstream uploadpools {

    server 192.168.103.124:80 weight=1;

}

#default_pools爲默認的服務器池,即動態服務器池,有一個服務器,地址爲192.168.103.125,端口爲80.
upstream defaultpools {
    server 192.168.103.125:80 weight=1;
}

#提示:須要增長一臺測試Web節點Web03(ip:192.168.103.125),配置與Web01,Web02同樣。

下面利用location或if語句把不一樣的URI(路徑)請求,分給不一樣的服務器池處理,具體配置以下。

方案1:以location方案實現

//lb01
#將符合static的請求交給靜態服務器池static_pools,配置以下:
location /static/ {
    proxy_pass http://staticpools;
    include proxy.conf;
}

#將符合upload的請求交給上傳服務器池upload_pools,配置以下:
location /upload/ {
    proxy_pass http://uploadpools;
    include proxy.conf;
}

#不符合上述規則的請求,默認所有交給動態服務器池default_pools,配置以下:
location / {
    proxy_pass http://defaultpools;
    include proxy.conf;
}

方案2:以if語句實現。

[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            if ($request_uri ~* "^/static/(.*)$")
            {   
                proxy_pass http://staticpools/$1;
            }   

            if ($request_uri ~* "^/upload/(.*)$")
            {   
                proxy_pass http://uploadpools/$1;
 }  
            proxy_pass http://defaultpools;
            include proxy.conf;
        }
    }
}

 

從新加載配置生效,以下:

[root@lb01 /]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload

暫時不要馬上測試成果,爲了實現上述代理的測試,還須要在Web01和Web02上作節點的測試配置,才能更好地展現測試效果。
以Web01做爲static靜態服務,地址端口爲:192.168.103.123:80,須要事先配置一個用於測試靜態的地址頁面,並測試訪問,肯定它會返回正確結果。操做步驟以下:

// web01
[root@web01 /]# mkdir -p /usr/local/nginx/html/www/static
[root@web01 /]# echo "static_pools www" >> /usr/local/nginx/html/www/static/index.html
[root@web01 /]# mkdir -p /usr/local/nginx/html/bbs/static
[root@web01 /]# echo "static_pools bbs" >> /usr/local/nginx/html/bbs/static/index.html
[root@web01 /]# curl http://www.yunjisuan.com/static/index.html      #這裏的www.yunjisuan.com是解析過的Web01的本地IP
static_pools www
[root@web01 /]# curl http://bbs.yunjisuan.com/static/index.html      #這裏的bbs.yunjisuan.com是解析過的Web01的本地IP
static_pools bbs
#提示:測試的靜態地址爲http://www.yunjisuan.com/static/index.html,注意,是帶static路徑的地址。

以Web02做爲upload上傳服務,地址端口爲:192.168.103.124:80,須要事先配置一個用於測試上傳服務的地址頁面,並測試訪問,肯定它會返回正確結果。操做步驟以下:

// web02
[root@web02 ~]# mkdir -p /usr/local/nginx/html/www/upload/
[root@web02 ~]# echo "upload_pools www" >> /usr/local/nginx/html/www/upload/index.html
[root@web02 ~]# mkdir -p /usr/local/nginx/html/bbs/upload
[root@web02 ~]# echo "upload_pools bbs" >> /usr/local/nginx/html/bbs/upload/index.html
[root@web02 ~]# curl http://www.yunjisuan.com/upload/index.html      #這裏的www.yunjisuan.com是解析過的Web02的本地IP
upload_pools www
[root@web02 ~]# curl http://bbs.yunjisuan.com/upload/index.html      #這裏的bbs.yunjisuan.com是解析過的Web02的本地IP
upload_pools bbs
#提示:測試的上傳地址爲http://www.yunjisuan.com/upload/index.html,注意,是帶upload路徑的地址。

在Web03做爲動態服務節點,地址端口爲192.168.103.125:80,一樣須要事先配置一個默認的地址頁面,並測試訪問,肯定它會返回正確結果。操做步驟以下:

[root@web03 /]# cd /usr/local/nginx/html/www
[root@web03 www]# echo "default_pools" > index.html
[root@web03 www]# curl http://www.yunjisuan.com
default_pools

以上準備了上臺Web節點服務器,分別加入到了upstream定義的不一樣服務器池,表明三組不一樣的業務集羣組,從本機經過hosts解析各自的域名,而後測試訪問,其地址與實際訪問的內容輸出請對照下表:

節點 IP及端口 測試地址 字符串爲表明業務
web01 192.168.103.123:80 http://www.yunjisuan.com/static/index.html static_pools
web02 192.168.103.124:80 http://www.yunjisuan.com/upload/index.html upload_pools
web03 192.168.103.125:80 http://www.yunjisuan.com default_pools

使用客戶端計算機訪問測試時,最好選用集羣之外的機器,這裏先在瀏覽器客戶端的hosts文件裏把www.yunjisuan.com解析到Nginx反向代理服務器的IP,而後訪問上述URL,看代理是否是把請求正確地轉發到了指定的服務器上。若是能夠獲得與上表對應的內容,表示配置的Nginx代理分發的徹底正確,由於若是分發請求到錯誤的機器上就沒有對應的URL頁面內容,輸出會是404錯誤。 

[root@lb01 /]# curl http://www.yunjisuan.com/static/index.html
static_pools www
[root@lb01 /]# curl http://www.yunjisuan.com/upload/index.html
upload_pools www
[root@lb01 /]# curl http://www.yunjisuan.com
default_pools

實際配置以下:

// lb01
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # static_pools爲靜態服務器池,有一個服務器,地址爲192.168.103.123,端口爲80. upstream staticpools { server 192.168.103.123:80 ; } # upload_pools爲上傳服務器池,有一個服務器地址爲192.168.103.124,端口爲80. upstream uploadpools { server 192.168.103.124:80 ; } # default_pools爲默認的服務器池,即動態服務器池,有一個服務器,地址爲192.168.103.125,端口爲80. upstream defaultpools { server 192.168.103.125:80 ; } server { listen 80; server_name www.yunjisuan.com; location /static/ { proxy_pass http://staticpools; include proxy.conf; } location /upload/ { proxy_pass http://uploadpools; include proxy.conf; } location / { proxy_pass http://defaultpools; include proxy.conf; } } }

 

根據URL目錄地址轉發的應用場景

  • 根據HTTP的URL進行轉發的應用狀況,被稱爲第7層(應用層)的負載均衡,而LVS的負載均衡通常用於TCP等的轉發,所以被稱爲第4層(傳輸層)的負載均衡。
  • 在企業中,有時但願只用一個域名對外提供服務,不但願使用多個域名對應同一個產品業務,此時就須要在代理服務器上經過配置規則,使得匹配不一樣規則的請求會交給不一樣的服務器池處理。這類業務有:
  • 業務的域名沒有拆封或者不但願拆分,但但願實現動靜分離,多業務分離,這在前面已經講解過案例了。
  • 不一樣的客戶端設備(例如:手機和PC端)使用同一個域名訪問同一個業務網站,就須要根據規則將不一樣設備的用戶請求交給後端不一樣的服務器處理,以便獲得最佳用戶體驗。這也是很是重要的,接下來,我就帶同窗們看看這類的相關案例。

五、根據客戶端的設備(user_agent)轉發實踐需求

  在企業中,爲了讓不一樣的客戶端設備用戶訪問有更好的體驗,須要在後端架設不一樣服務器來知足不一樣的客戶端訪問,例如:移動客戶端訪問網站,就須要部署單獨的移動服務器及程序,體驗才能更好,並且移動端還分蘋果,安卓,Ipad等,在傳統的狀況下,通常用下面的辦法解決這個問題。

  • 常規4層負載均衡解決方案架構
      在常規4層負載均衡架構下,可使用不一樣的域名來實現這個需求,例如,人爲分配好讓移動端用戶訪問wap.yunjisuan.com,PC客戶端用戶訪問www.yunjisuan.com,經過不一樣域名來引導用戶到指定的後端服務器,該解決方案的架構圖以下:

     

       此解決方案的最大問題就是不一樣客戶端的用戶要記住對應的域名!而絕大多數用戶只會記住www.yunjisuan.com,不會記住wap.yunjisuan.com,這樣一來就會致使用戶體驗不是很好。有沒有辦法讓全部客戶端用戶只訪問一個統一的www.yunjisuan.com這個地址,還能讓不一樣客戶端設備都能有更好的訪問體驗呢?固然有!那就是下面的第7層負載均衡解決方案。

  • 第7層負載均衡解決方案
      在第7層負載均衡架構下,就能夠不須要人爲拆分域名了,對外只須要用一個域名,例如www.yunjisuan.com,經過獲取用戶請求中的設備信息(利用$http_user_agent獲取),根據這些信息轉給後端合適的服務器處理,這個方案最大好處就是不須要讓用戶記憶多個域名了,用戶只須要記住主網站地址www.yunjisuan.com,剩下的由網站服務器處理,這樣的思路大大地提高了用戶訪問體驗,這是當前企業網站很是經常使用的解決方案。
    下面咱們就來說解此方案,下圖描述了上述解決方案相應的架構邏輯圖

5.一、根據客戶端設備(user_agent)轉發請求實踐

這裏仍是使用static_pools,upload_pools做爲本次實驗的後端服務器池。下面先根據計算機客戶端瀏覽器的不一樣設置對應的匹配規則。(因爲沒有合適的實驗驗證環境,這裏僅做需求實現的細節講解)

//lb01
location / {
    if ($http_user_agent ~* "MSIE")
    # 若是請求的瀏覽器爲微軟IE瀏覽器(MSIE),則讓請求由static_pools池處理
    {
        proxy_pass http://staticpools;
    }
    if ($http_user_agent ~* "Chrome")
    # 若是請求的瀏覽器爲谷歌瀏覽器(Chrome),則讓請求由upload_pools池處理
    {
        proxy_pass http://uploadpools;
    }
    # 其餘客戶端,由default_pools處理
    proxy_pass http://defaultpools;
    include proxy.conf;
}

 

 

除了針對瀏覽器外,上述「$http_user_agent」變量也可針對移動端,好比安卓,蘋果,Ipad設備進行匹配,去請求指定的服務器,具體細節配置以下:

//lb01
location / {
    if ($http_user_agent ~* "android")
    {
        proxy_pass http://android_pools;    #這裏是android服務器池
    }
    if ($http_user_agent ~* "iphone")
    {
        proxy_pass http://iphone_pools;    #這裏是iphone服務器池
    }
    proxy_pass http://pc_pools;     #這裏是默認的pc服務器池
    include extra/proxy.conf;
}
  • 這部分的測試同窗們能夠回家經過局域網的Wifi功能來實現,用手機等鏈接到wifi,而後訪問服務器的IP測試就能夠了。測試時,請用節點的第一個虛擬主機請求測試,這樣就不須要本地hosts域名解析了,由於手機端測試作hosts解析也不容易,固然有公網的域名和服務器測試最佳,這部分的配合和測試與瀏覽器設備實踐幾乎同樣,所以,這裏的測試就留給同窗們了,看看能不能達到你想的測試效果?
  • 此外,查找移動設備的user_agent對應的具體名稱時,仍是先用對應的設備經過IP地址訪問節點服務器,而後看訪問日誌,注意IP訪問只找第一個虛擬主機的網站。
192.168.0.110--[28/Jul/2017:02:12:10 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)""-" 
#PCwindows訪問日誌

192.168.0.106--[28/Jul/2017:02:12:22 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.0 Mobile/14G60 Safari/602.1""-"

#蘋果iphone6手機設備訪問的日誌。

六、根據文件擴展名實現代理轉發

除了根據URI路徑及user_agent轉發外,還能夠實現根據文件擴展名進行轉發(這裏僅以細節配置做爲講解內容,如需測試請同窗們自行實驗)

相關server配置

#先看看location方法的匹配規則,以下:
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
    proxy_pass http://static_pools;
    include proxy.conf;
}

#下面是if語句方法的匹配規則:
if ($request_uri ~* ".*\.(php|php5)$")
{
    proxy_pass http://php_server_pools;
}

if ($request_uri ~* ".*\.(jsp|jsp*|do|do*)$")
{
    proxy_pass http://java_server_pools;
}

根據擴展名轉發的應用場景

可根據擴展名實現資源的動靜分離訪問,如圖片,視頻等請求靜態服務器池,PHP,JSP等請求動態服務器池。

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
    proxy_pass http://static_pools;
    include proxy.conf;
}

location ~ .*\.(php|php3|php5)$ {
    proxy_pass http://dynamic_pools;
    include proxy.conf
}

在開發沒法經過程序實現動靜分離的時候,運維能夠根據資源實體進行動靜分離,而不依賴於開發,具體實現策略是先把後端的服務器分紅不一樣的組。注意,每組服務器的程序都是相同的,由於開發沒有把程序拆開,分組後,在前端代理服務器上經過講解過的路徑,擴展名進行規則匹配,從而實現請求的動靜分離。

七、Nginx負載均衡檢測節點狀態

淘寶技術團隊開發了一個Tengine(Nginx的分支)模塊Nginx_upstream_check_module,用於提供主動式後端服務器健康檢查。經過它能夠檢測後端realserver的健康狀態,若是後端realserver不可用,則全部的請求就不會轉發到該節點上。
Tengine原生支持這個模塊,而Nginx則須要經過打補丁的方式將該模塊添加到Nginx中。補丁下載地址:https://github.com/yaoweibin/nginx_upstream_check_module。下面介紹如何使用這個模塊。

  1. 安裝nginx_upstream_check_module模塊
    #系統已經安裝了nginx-1.10.2軟件
    [root@lb01 ~]# /usr/local/nginx/sbin/nginx -V
    nginx version: nginx/1.10.2
    
    #下載補丁包
    [root@lb01 ~]# wget https://codeload.github.com/786744873/nginx_upstream_check_module/zip/master
    [root@lb01 ~]# unzip master
    [root@lb01 ~]# ls
    anaconda-ks.cfg  install.log  install.log.syslog  master  nginx-1.10.2.tar.gz  nginx_upstream_check_module-master
    [root@lb01 nginx-1.10.2]# mv ~/nginx_upstream_check_module-master /usr/src/
    
    #由於是對源程序打補丁,因此還須要Nginx源程序
    [root@lb01 ~]# cd /usr/src/nginx-1.10.2/
    [root@lb01 nginx-1.10.2]# patch -p0 < /usr/src/nginx_upstream_check_module-master/check_1.9.2+.patch
    patching file src/http/modules/ngx_http_upstream_hash_module.c
    patching file src/http/modules/ngx_http_upstream_ip_hash_module.c
    patching file src/http/modules/ngx_http_upstream_least_conn_module.c
    patching file src/http/ngx_http_upstream_round_robin.c
    patching file src/http/ngx_http_upstream_round_robin.h
    
    #備份源安裝程序
    [root@lb01 nginx-1.10.2]# cd /usr/local/
    [root@lb01 local]# ls
    bin  etc  games  include  lib  lib64  libexec  nginx  sbin  share  src
    [root@lb01 local]# mv nginx{,.ori}
    [root@lb01 local]# ls
    bin  etc  games  include  lib  lib64  libexec  nginx.ori  sbin  share  src
    [root@lb01 local]# cd /usr/src/nginx-1.10.2/
    
    #從新進行編譯,編譯的參數要和之前一致,最後加上 --add-module=/usr/src/nginx_upstream_check_module-master/
    
    [root@lb01 nginx-1.10.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/
    [root@lb01 local]# /usr/local/nginx/sbin/nginx -V
    nginx version: nginx/1.10.2
    built by gcc 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) 
    built with OpenSSL 1.0.1e-fips 11 Feb 2013
    TLS SNI support enabled
    configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/
    
    #拷貝源配置文件到當前Nginx的安裝目錄下
    [root@lb01 local]# pwd
    /usr/local
    [root@lb01 local]# cp nginx.ori/conf/nginx.conf nginx/conf/
    cp: overwrite `nginx/conf/nginx.conf'? y
    [root@lb01 local]# cp nginx.ori/conf/proxy.conf nginx/conf/
    [root@lb01 local]# /usr/local/nginx/sbin/nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
  2. 配置Nginx健康檢查,以下:
    [root@lb01 local]# vim nginx/conf/nginx.conf
    
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
    
        # static_pools爲靜態服務器池,有一個服務器,地址爲192.168.103.123,端口爲80.
        upstream staticpools {
            server 192.168.103.123:80 ;
            check interval=3000 rise=2 fall=5 timeout=1000 type=http;   #對static服務器池開啓健康監測
        }
    
        # upload_pools爲上傳服務器池,有一個服務器地址爲192.168.103.124,端口爲80.
        upstream uploadpools {
            server 192.168.103.124:80 ;
            check interval=3000 rise=2 fall=5 timeout=1000 type=http;   #對static服務器池開啓健康監測
        }
    
        # default_pools爲默認的服務器池,即動態服務器池,有一個服務器,地址爲192.168.103.125,端口爲80.
        upstream defaultpools {
            server 192.168.103.125:80 ;
            check interval=3000 rise=2 fall=5 timeout=1000 type=http;   #對static服務器池開啓健康監測
        }
    
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                if ($http_user_agent ~* "MSIE")
                #若是請求的瀏覽器爲微軟IE瀏覽器(MSIE),則讓請求由static_pools池處理
                {
                    proxy_pass http://staticpools;
                }
                if ($http_user_agent ~* "Chrome")
                #若是請求的瀏覽器爲谷歌瀏覽器(Chrome),則讓請求由upload_pools池處理
                {
                    proxy_pass http://uploadpools;
                }
                proxy_pass http://defaultpools;
                include proxy.conf;
            }
            location /status {
                check_status;           #啓動健康檢查模塊
                access_log off;         #關閉此location的訪問日誌記錄
            }
    
        }
    }
  3. 重啓lb1的nginx服務
    注意此處必須重啓Nginx,不能從新加載

    [root@lb01 local]# killall nginx
    [root@lb01 local]# /usr/local/nginx/sbin/nginx
    [root@lb01 local]# netstat -antup | grep nginx
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      20908/nginx: master 

    check interval=3000 rise=2 fall=5 timeout=1000 type=http;
    上面配置的意思時,對static_pools這個負載均衡條目中的全部節點,每隔3秒檢測一次,請求2次正常則標記realserver狀態爲up,若是檢測5次都失敗,則標記realserver的狀態爲down,超時時間爲1秒,檢查的協議是HTTP。
    詳細用法見官網:http://tengine.taobao.org/document_cn/http_upstream_check_cn.html

    訪問頁面時,顯示以下圖所示:

     

     關閉任意一個RS節點後(3個Web服務器任選一個關閉nginx服務)

proxy_next_upstream 參數補充

當Nginx接收後端服務器返回proxy_next_upstream參數定義的狀態碼時,會將這個請求轉發給正常工做的後端服務器,例如500,502,503,504,此參數能夠提高用戶的訪問體驗,具體配置以下:

server {
    listen 80;
    server_name www.yunjisuan.com;
    location / {
        proxy_pass http://static_pools;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        include proxy.conf;
    }
}
相關文章
相關標籤/搜索