nginx 反向代理(proxy)與負載均衡(upstream)應用實踐

集羣介紹

集羣就是指一組(若干個)相互獨立的計算機,利用高速通訊網絡組成的一個較大的計算機服務系統,每一個集羣節點(即集羣中的每臺計算機)都是運行各自服務的獨立服務器。這些服務器之間能夠彼此通訊,協同向用戶提供應用程序,系統資源和數據,並以單一系統的模式加以管理。當用戶客戶機請求集羣系統時,集羣給用戶的感受就是一個單一獨立的服務器,而實際上用戶請求的是一組集羣服務器。php

集羣特色

1. 高性能css

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

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

2. 價格有效性java

一套系統集羣架構,只須要幾臺或者樹十臺服務器主機便可,與動輒價值上百萬元的專用超級計算機相比便宜了不少。在達到一樣性能需求的條件下,採用計算機集羣架構比採用同等運算能力的大型計算機具備更高的性價比。nginx

3. 可伸縮性web

當服務負載,壓力增大時,針對集羣系統進行簡單的擴展便可知足需求,且不會下降服務質量。算法

一般狀況下,硬件設備若想擴展性能,不得不增長新的cpu和存儲設備,若是加不上去了,就不得不增長新的cpu和存儲設備,若是加不上去了,就不得不購買更高性能的服務器。若是採用集羣技術,則只須要將新的單個服務器加入到現有集羣架構中便可,從訪問的客戶角度來看,系統服務不管是連續性仍是性能上都幾乎沒有變化,系統在不知不覺中完成了升級,加大了訪問能力,輕鬆地實現了擴展。集羣系統中的節點樹木能夠增加到幾千乃至上萬個,其伸縮性遠超過單臺超級計算機。數據庫

4. 高可用性編程

單一的計算機系統總會面臨設備損毀的問題,如cpu,內存,主板,電源,硬盤等,只要一個部件壞掉,這個計算機系統就可能會宕機,沒法正常提供服務,在集羣系統中,儘管部分硬件和軟件也仍是會發生故障,但整個系統的服務能夠是7*24可用的。

集羣架構技術可使得系統在若干硬件設備故障發生時仍能夠繼續工做,這樣就將系統的停機時間減小到了最小。集羣系統在提升系統可靠性的同時,也大大減少了系統故障帶來的業務損失。

5. 透明性

多個獨立計算機組成的集羣系統構成一個虛擬服務器。用戶或客戶端程序訪問集羣系統時,就像訪問一臺高性能,高可用的服務器同樣,集羣中一部分服務器的上線,下線不會中斷整個系統服務,這對用戶也是透明的。

6. 可管理性

整個系統可能在物理上很大,但其實容易管理,就像管理一個單一映像系統同樣,可經過ssh服務管理

7. 可編程性

在集羣系統上,容易開發及修改各種應用程序

集羣的分類

集羣架構按功能和結構能夠分紅以下幾類
負載均衡集羣 load balancing clusters,簡稱lbc或者lb
高可用性集羣 high-availability clusters,簡稱hac
高性能計算集羣 high-performance clusters,簡稱hpc
網絡計算 grid computing集羣

1. 負載均衡集羣

負載均衡羣集爲企業提供了更爲實用,性價比更高的系統架構解決方案,負載均衡集羣能夠把不少客戶集中的訪問請求壓力盡量平均地分攤在計算機集羣中處理,客戶訪問請求負載一般包括應用程序處理負載和網絡流量負載。這樣的系統很是適合使用同一組應用程序爲大量用戶提供服務的模式,每一個節點均可以承擔必定的訪問請求負載壓力,而且能夠實現訪問請求在各節點之間動態分配,以實現負載均衡。

負載均衡集羣運行時,通常經過一個或多個前端負載均衡器將客戶訪問請求分發到後端的一組服務器上,從而達到整個系統的高性能和高可用性。通常高可用性羣集和負載均衡羣集會使用相似的技術,或同時具備高用性與負載均衡的特色。

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

 

2. 高可用集羣 

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

當集羣中的一個節點系統發生故障時,運行着的集羣服務會迅速做出反應,將該系統的服務分配到集羣中其餘正在工做的系統上運行。考慮到計算機硬件和軟件的容錯性,高可用性集羣的主要目的是使總體服務儘量可用。若是高可能性集羣中的主節點發生了故障,那麼這段時間內將由備節點代替它。備節點會徹底接管主節點(包括ip地址及其餘資源)提供服務。

高可用性集羣使服務器系統的運行速度和響應速度會盡量的快。他們常常利用在多臺機器上運行的冗餘節點和服務來相互跟蹤,若是某個節點失敗,它的替補者將在幾秒鐘或更短期內接管它的職責。

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

3. 高性能計算集羣

高性能計算集羣也稱並行計算。一般,高性能計算集羣涉及爲集羣開發的並行應用程序,以解決複雜的科學問題(天氣預報,石油勘探,核反應模擬等)。高性能計算集羣對外就好像一個超級計算機,這種超級計算機內部由數十至上萬個獨立服務器組成,而且在公共消息傳遞層上進行通訊以運行並行應用程序。

4. 網絡計算集羣

不多用

開源集羣軟件產品的選擇

nginx負載均衡集羣介紹

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

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

反向代理與負載均衡概念簡介

nginx僅僅是做爲nginx proxy反向代理使用的,由於這個反向代理功能表現的效果是負載均衡集羣的效果,咱們就稱爲nginx負載均衡。

lvs,其實現的功能只是對請求數據包的轉發,傳遞,其中dr模式明顯的特徵是從負載均衡下面的節點服務器來看,接收到的請求仍是來自訪問負載均衡器的客戶端的真實用戶,而反向代理就不同了,反向代理接收訪問用戶的請求後,會代理用戶從新發起請求代理下的節點服務器,最後把數據返回給客戶端用戶,在節點服務器看來,訪問的節點服務器的客戶端用戶就是反向代理服務器了,而非真實的網站訪問用戶。

lvs是轉發,僅僅只是幫用戶轉發,不會替代用戶請求,而nginx是接收用戶的請求而後從新發起請求去請求後面的節點。

實現nginx負載均衡的組件說明

nginx的功能就是 緩存 反向代理 負載均衡,而其自己就是一個反向代理的軟件。lvs是4層,nginx在1.9版本以前是7層,而1.9以上4 7層,haproxy 4 7層。

快速搭建nginx負載均衡環境

編譯安裝配置文件參考

yum install pcre pcre-devel -y
yum install openssl openssl-devel -y
注意:通常安裝軟件-devel都是必須安裝的
useradd www -s /sbin/nologin -M
cd /joker/
mkdir tools
cd tools/
wget -q http://nginx.org/download/nginx-1.6.3.tar.gz
cd nginx-1.6.3
./configure --user=www --group=www --with-http_ssl_module --with-http_stub_status_module --prefix=/application/nginx-1.6.3/
make
make install
cd /application/nginx-1.6.3/
ln -s /application/nginx-1.6.3/ /application/nginx
/application/nginx/sbin/nginx -t      # 檢 查語法
/application/nginx/sbin/nginx         # 啓動
/application/nginx/sbin/nginx -V      # 版本
/application/nginx/log/error.log      # 錯誤日誌
netstat -ntlp                         # 查看啓動是否成功

[root@Poppy conf]# cat nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
# 關鍵字,日誌文件,錯誤日誌級別
error_log logs/error.log error;
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"';   
    # 訪問日誌,main就是讀http裏面的main日誌變量
    # access_log logs/www_access.log main;
    include extra/*.conf;
}

[root@Poppy extra]# cat bbs.conf 
    server {
        listen       80;
        server_name  bbs.joker.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
    }

yum安裝的nginx配置文件修改參考

[root@joker nginx]# tree 
.
├── conf.d
│   ├── walle.conf.bak
│   └── www.conf
├── default.d
├── fastcgi.conf
├── fastcgi.conf.default
├── fastcgi_params
├── fastcgi_params.default
├── koi-utf
├── koi-win
├── mime.types
├── mime.types.default
├── nginx.conf       配置文件,將conf到conf.d
├── nginx.conf.default
├── scgi_params
├── scgi_params.default
├── uwsgi_params
├── uwsgi_params.default
└── win-utf


[root@joker conf.d]# cat bbs.conf 
server {
    listen       80;
    server_name  bbs.joker.com;

    location / {
        root /data/bbs; # 根目錄爲web
        index index.html;
    }
}
[root@joker conf.d]# cat blog.conf 
server {
    listen       80;
    server_name  blog.joker.com;

    location / {
        root /data/blog; # 根目錄爲web
        index index.html;
    }
}

[root@joker data]# cat blog/index.html 
blog sfdsf
[root@joker data]# cat bbs/index.html 
bbs fdfd

做爲nginx負載的服務器配置以下,紅色區域

[root@Poppy extra]# cat ../nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
# 關鍵字,日誌文件,錯誤日誌級別
error_log logs/error.log error;
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"';   
    # 訪問日誌,main就是讀http裏面的main日誌變量
    # access_log logs/www_access.log main;
    upstream www_server_pools{       # 定義負載名稱
        server IP1:80 weight=1;      # 後端服務器地址,後面會詳解
        server IP2:80 weight=1;
 }
    include extra/bbs.conf;
    include extra/blog.conf;
}
[root@Poppy extra]# cat bbs.conf 
    server {
        listen       80;
        server_name  bbs.joker.com;
        location / {
           root html/bbs;
           index index.html;
        }
    }
[root@Poppy extra]# cat blog.conf 
    server {
        listen       80;
        server_name  blog.joker.com;
        location / {
            proxy_pass http://www_server_pools; # 經過proxy_pass模塊拋給upstream模塊 }
    }

客戶端訪問,即便後端服務器有宕機的,也不會影響業務,會自動剔除有故障的後端服務器,基於端口的健康檢查

[root@Poppy extra]# curl bbs.joker.com
bbs       訪問本身的web服務,沒有進行負載
[root@Poppy extra]# curl blog.joker.com
bbs fdfd

nginx負載均衡核心組件介紹

1. nginx upstream模塊

ginx的負載均衡功能依賴於ngx_http_upstream_module模塊,所支持的代理方式包括proxy_pass,fastcgi_pass,memcached_pass等,新版nginx軟件支持的方式有所增長
ngx_http_upstream_module模式容許nginx定義一組或多組節點服務器組,使用能夠經過porxy_pass代理方式把網站的請求發送到事先定義好的對應upstream組的名字上。

2. upstream語法

upstream www_server_pools{
upstream是關鍵字必需要有,後面的www_server_pools爲一個upstream集羣組的名字,能夠本身起名,調用時就用這個名字
server 10.0.0.1 weight=1;
server關鍵字是固定的,後面能夠接域名或ip,若是不指定端口,默認是80端口。weight表明權重,數值越大被分配的請求越多,結尾有分號。
server 10.0.0.2 weight=2;
server 10.0.0.3 weight=3;
}

    upstream www_server_pools{
        server ip1:80 weight=1;
        server ip2:80 weight=2 max_fails=1 fail_timeout=10s backup;   
bakcup就是熱備機器 1此連續連續檢測失敗,間隔10秒再次檢測,除了backup都是默認設置的
server www.joker.com:8080 weight=3; 域名
server unix:/tmp/socketfile socket文件 }

特別注意,若是nginx代理的是cache服務,可能須要使用hash算法,此時若宕機,可經過設置down參數確保客戶端確保客戶端用戶按照當前的hash算法訪問,這一點很重要。

    upstream www_server_pools{
        ip_hash;
        server ip1:80 down;
        server ip2:80 ;
    }  
hash算法沒法使用權重和backup,即便有也不生效

upstream模塊的內容應放於nginx.conf配置的http{}標籤內,默認調度算法是wrr,即權重輪詢

upstream模塊調度算法

調度算法通常分爲兩類,第一類爲靜態調度算法,即負載均衡器根據自身設定的規則進行分配,不須要考慮後端節點服務器的狀況,例如 rr,wrr,ip_hash等都屬於靜態調度算法

第二類爲動態調度算法,即負載均衡器會根據根據後端節點的當前狀態決定是否分發請求,例如 鏈接數少的優先得到請求,響應時間短的優先得到請求,如 least_conn,fair等

1. rr輪詢,默認調度算法

接收客戶端請求順序把客戶端的請求逐一分配到不一樣的後端節點服務器

2. wrr權重輪詢

權重和用戶訪問成正比,權重值越大,被轉發的請求也就越多,可根據服務器配置來判斷權重值

server 10.0.0.1 weight=1;
server 10.0.0.2 weight=2;

若是有30個請求,其中20個會向10.0.0.2訪問,剩下的10個向10.0.0.1訪問

3. ip_hash

每一個請求按客戶端ip的hash結果分配,當新的請求到達時,先將其客戶端ip經過哈希算法哈希出一個值,在隨後的客戶端請求中,客戶ip的哈希值只要相同,就會被分配至同一臺服務器,該調度算法能夠解決動態網頁的session共享問題,但有時會致使請求分配不均,即沒法保證1:1的負載均衡,由於在國內大多數公司都是nat上網模式,多個客戶端會對應一個外部ip,因此,這些客戶端會被分配到同一個節點服務器,從而致使請求分配不均。

 upstream www_server_pools{
        ip_hash;
        server ip1:80 down;
        server ip2:80 ;
    }  
    hash算法沒法使用權重和backup,即便有也不生效

4. fair動態調度算法

此算法會根據後端節點服務器的響應時間來分配請求,響應時間短的優先分配。這是更加智能的調度算法。此種算法能夠依據頁面大小和加載時間長短智能地進行負載均衡,也就是根據後端服務器的響應時間來分配請求,響應時間短的優先分配。nginx自己不支持fair調度算法,需下載nginx的相關模塊upstream fair。

upstream joker_lb{
server 1.0.0.1;
server 1.0.0.2;
fair;
}

5. least_conn

根據後端節點的鏈接數來決定分配狀況,哪一個機器鏈接數少就分發

還有2個是url_hash和一致性hash算法,後端服務爲緩存服務效果顯著。這裏就不說了

http_proxy_module模塊

nginx代理功能是經過http proxy模塊來實現的,默認在安裝nginx時已經安裝了http proxy模塊,所以能夠直接使用http proxy模塊

 

當用戶訪問域名時攜帶www.joker.com請求nginx反向代理服務器,可是反向代理向下面節點從新發起請求時,默認並無在請求頭裏告訴節點服務器要找哪臺虛擬主機,因此,web節點服務器接收請求後發現沒有主機頭信息,所以,節點服務器就把第一個虛擬主機發給了反向代理。解決這個問題的方法就是當反向代理向後臺從新發送請求時,要攜帶主機頭信息,以明確告訴節點服務器要找哪一個虛擬主機。

[root@Poppy extra]# cat blog.conf 
    server {
        listen       80;
        server_name  blog.joker.com;
        location / {
            proxy_pass http://www_server_pools;
            proxy_set_header Host $host; 將攜帶用戶的主機頭信息
        }
    }

咱們發現,節點的訪問日誌存儲的是代理服務器的ip,也就是負載均衡的機子,咱們如何將用戶的真實ip獲取到呢,以下配置

[root@Poppy extra]# cat blog.conf 
    server {
        listen       80;
        server_name  blog.joker.com;
        location / {
            proxy_pass http://www_server_pools;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr; 注意要與攜帶請求頭設置主機頭分開寫
        }
    }

注意,反向代理這塊配好了,節點服務器上須要的訪問日誌要記錄用戶的真實ip,必須進行日誌格式配置,這樣才能把代理傳過來的x-forwarded-for頭信息記錄下來

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

固然,默認是有的

配置文件能夠經過include包含設置,這樣看上去跟工整,目錄須要注意下

[root@Poppy ~]# cat /application/nginx/conf/extra/blog.conf   
    server {
        listen       80;
        server_name  blog.joker.com;
        location / {
            proxy_pass http://www_server_pools;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            include proxy.conf;
        }
    }

[root@Poppy ~]# cat /application/nginx/conf/extra/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 64;

根據url中的目錄地址實現代理轉發

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

此架構圖適合網站前端只使用同一個域名提供服務的場景,例如訪問www.joker.com,而後當用用戶請求www.joker.com/static地址的時候,代理會分配請求到靜態服務器池請求數據;當用戶請求www.joker.com/upload地址的時候,代理會分配請求到上傳服務器池處理數據;當用戶請求www.joker.com地址的時候,即不包含上述指定的目錄地址路徑時,代理會分配請求到默認的動態服務器池請求數據 

  • 用戶請求www.joker.com/upload地址時,實現由upload上傳服務器池處理請求
  • 用戶請求www.joker.com/static地址時,實現由靜態服務器池處理請求
  • 除此以外,對於其餘的訪問請求,所有由默認的動態服務器池處理請求

咱們來配置下upstream服務器池,http標籤中以下配置

    upstream static_pools {
            server 1:80 weight=1;
        }
        upstream upload_pools {
            server 2:80 weight=1;
        }
        upstream default_pools {
            server 3:80 weight=1;
        }

下面是location的配置,server標籤

    server {
        listen       80;
        server_name  blog.joker.com;
        location /static/ {
            proxy_pass http://static_pools;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        location /upload/ {
            proxy_pass http://upload_pools;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        location / {
            proxy_pass http://default_pools;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
    }
    
    
    經過用if來判斷請求路徑而後反向代理,其效果跟上面是同樣的
    server {
        listen       80;
        server_name  blog.joker.com;
            
        if ($request_uri ~* "/^static/(.*)$")
            {
                proxy_pass http://static_pools/$1;
            }
        if ($request_uri ~* "/^upload/(.*)$")
            {
                proxy_pass http://upload_pools/$1;
            }
        location / {
                proxy_pass http://default_pools;
                include proxy.conf;
            }
     }

根據客戶端設備(user_agent)轉發實踐

1. 根據客戶端設備(user_ange)轉發實踐需求

爲了讓不一樣的客戶端設備用戶有更好的體驗,須要在後端架設不一樣的服務器來知足不一樣的客戶端訪問,例如 移動客戶端訪問網站,就須要部署單獨的移動服務器及程序,體驗才能更好,並且移動端還分apple,ipad等

在常規4層負載架構下,可使用不一樣的域名來實現這個需求,例如 移動端用戶訪問wap.joker.com,pc端用戶訪問www.joker.com,此解決方案最大的問題就是不一樣的客戶端須要記住域名,而絕大多數用戶只會記住www.joker.com,這樣一來就會致使用戶體驗不是很好。

 

在7層負載均衡架構下,就能夠不須要拆分域名了,對外只須要一個域名便可,例如 www.joker.com,而後經過獲取用戶請求中的設備信息(利用 $http_user_agent獲取),根據這些信息轉給後端合適的服務器處理。

2. 根據客戶端設備(user_ange)轉發請求實踐

        server {
            listen       80;
            server_name  blog.joker.com;
            location / {
                if ($http_user_agent ~* "MSIE"){
                    proxy_pass http://static_pools;
                }
                if ($http_user_agent ~* "Chrome"){
                    proxy_pass http://upload_pools;
                }
                proxy_pass http://default_pools;
                include proxy.conf
            }
        }

須要特別說明的是,當你沒法知道客戶端設備字符串名字(例如Chrome,MSIE,Firefox這樣的字符串)時,能夠先用這些瀏覽器訪問對應的節點服務器,而後根據訪問日誌中的$http_user_agent格式記錄的日誌確認。

3. 根據文件擴展名實現代理轉發

除了根據url路徑及user_agent轉發外,還能夠實現根據文件擴展名進行轉發。

        server {
             listen       80;
             server_name  blog.joker.com;
             location ~ .*.(gif|jpg|jpeg|png|bmp|swf|css|js)${
                proxy_pass http://static_pools;
                include proxy.conf
            }
          }
             
        server {
            listen       80;
            server_name  blog.joker.com;
            location / {
            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等請求動態服務器池。

節點故障監控

能夠經過zabbix等監控節點服務器的web服務狀態,起到預警的做用。

相關文章
相關標籤/搜索