nginx作負載均衡器以及proxy緩存配置

關於nginx的安裝和基本配置請參考nginx,本文在原基礎上完成如下幾個功能:css

  • 結合proxy和upstream模塊實現nginx負載均衡
  • 結合nginx_upstream_check_module模塊實現後端服務器的健康檢查
  • 使用nginx-sticky-module擴展模塊實現Cookie會話黏貼(session-sticky效果)
  • 使用proxy模塊實現靜態文件緩存
  • 使用ngx_cache_purge實現更強大的緩存清除功能

更多內容見個人博客 http://seanlook.com/html

1. 安裝及模塊說明

上面提到的3個模塊都屬於第三方擴展模塊,須要提早下好源碼,而後編譯時經過--add-moudle=src_path一塊兒安裝。mysql

注意:linux

  • 使用 nginx_upstream_check_module(簡記爲m1) 時要先爲nginx打上相應版本的patch,個人nginx版本爲 1.6.3,因此patch對應 m1 解壓後目錄下的check_1.5.12+.patch,因此進入nginx源碼目錄,執行 patch -p1 ...(見下方示例)
  • nginx-sticky-module-ng(簡記爲m2) 模塊能夠單獨使用,可是由於m1監控檢查的方式是依賴於m2的,因此要使用m2,還要對m1打上patch,進入m2源碼目錄,執行 patch -p0...

編譯示例:(CentOS 6.5 x86_64, nginx 1.6.3)nginx

# yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl--devel pcre pcre-devel

# cd nginx-1.6.3
# patch -p1 < ../nginx_upstream_check_module-0.3.0/check_1.5.12+.patch

# cd ../nginx-sticky-module-ng-1.2.5
# patch -p0 < ../nginx_upstream_check_module-0.3.0/nginx-sticky-module.patch

# ./configure --prefix=/usr/local/nginx-1.6 --with-pcre 
--with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-http_realip_module 
--add-module=../nginx_upstream_check_module-0.3.0 --add-module=../nginx-sticky-module-ng-1.2.5 --add-module=../ngx_cache_purge-2.3
# make && make install

若是你想在已安裝好的nginx上添加第三方模塊,依然須要從新編譯,但爲了避免覆蓋你原有的配置,請不要make install,而是直接拷貝可執行文件:c++

# nginx -V              //能夠看到原來的編譯選項,下面用到
# ./configure ... --add-module=..       //你的第三方模塊
# make           //make後不要install,改用手動拷貝。先備份
# cp objs/nginx /usr/local/nginx-1.6/sbin/nginx

2. nginx-sticky-module

項目地址:https://bitbucket.org/nginx-goodies/nginx-sticky-module-nggit

這個模塊的做用是經過cookie黏貼的方式未來自同一個客戶端(瀏覽器)的請求發送到同一個後端服務器上處理,這樣必定程度上能夠解決多個backend servers的session同步的問題 —— 由於再也不須要同步,而RR輪詢模式必需要運維人員本身考慮session同步的實現。github

另外內置的 ip_hash 也能夠實現根據客戶端IP來分發請求,但它很容易形成負載不均衡的狀況,而若是nginx前面有CDN網絡或者來自同一局域網的訪問,它接收的客戶端IP是同樣的,容易形成負載不均衡現象。淘寶Tengine的 ngx_http_upstream_session_sticky_module 也是相似的功能。nginx-sticky-module的cookie過時時間,默認瀏覽器關閉就過時,也就是會話方式。web

這個模塊並不合適不支持 Cookie 或手動禁用了cookie的瀏覽器,此時默認sticky就會切換成RR。它不能與ip_hash同時使用。算法

nginx-lb-sticky.jpg

2.1 sticky配置

upstream backend {
    server 172.29.88.226:8080 weight=1;
    server 172.29.88.227:8080 weight=1;
    sticky;
}

配置起來超級簡單,通常來講一個sticky指令就夠了。

sticky [name=route] [domain=.foo.bar] [path=/] [expires=1h] [hash=index|md5|sha1] [no_fallback];

  • name: 能夠爲任何的 string 字符,默認是 route
  • domain:哪些域名下可使用這個 cookie
  • path:哪些路徑對啓用 sticky,例如 path/test,那麼只有 test 這個目錄纔會使用 sticky 作負載均衡
  • expires:cookie 過時時間,默認瀏覽器關閉就過時,也就是會話方式。
  • no_fallbackup:若是設置了這個,cookie 對應的服務器宕機了,那麼將會返回502(bad gateway 或者 proxy error),建議不啓用

你在查看官方文檔可能會注意到裏面也有個 sticky 指令,要說它們的做用幾乎是同樣的,可是你可能注意到This directive is available as part of our commercial subscription.的說明 —— 這是nginx商業版本里纔有的特性。包括後面的check指令,在nginx的商業版本里也有對應的health_check(配在 location )實現幾乎同樣的監控檢查功能。

2.2 load-balance其它調度方案

這裏順帶介紹一下nginx的負載均衡模塊支持的其它調度算法:

  • 輪詢(默認) : 每一個請求按時間順序逐一分配到不一樣的後端服務器,若是後端某臺服務器宕機,故障系統被自動剔除,使用戶訪問不受影響。Weight 指定輪詢權值,Weight值越大,分配到的訪問機率越高,主要用於後端每一個服務器性能不均的狀況下。
  • ip_hash : 每一個請求按訪問IP的hash結果分配,這樣來自同一個IP的訪客固定訪問一個後端服務器,有效解決了動態網頁存在的session共享問題。固然若是這個節點不可用了,會發到下個節點,而此時沒有session同步的話就註銷掉了。
  • least_conn : 請求被髮送到當前活躍鏈接最少的realserver上。會考慮weight的值。
  • url_hash : 此方法按訪問url的hash結果來分配請求,使每一個url定向到同一個後端服務器,能夠進一步提升後端緩存服務器的效率。Nginx自己是不支持url_hash的,若是須要使用這種調度算法,必須安裝Nginx 的hash軟件包 nginx_upstream_hash 。
  • fair : 這是比上面兩個更加智能的負載均衡算法。此種算法能夠依據頁面大小和加載時間長短智能地進行負載均衡,也就是根據後端服務器的響應時間來分配請求,響應時間短的優先分配。Nginx自己是不支持fair的,若是須要使用這種調度算法,必須下載Nginx的 upstream_fair 模塊。

3. 負載均衡與健康檢查

嚴格來講,nginx自帶是沒有針對負載均衡後端節點的健康檢查的,可是能夠經過默認自帶的 ngx_http_proxy_module 模塊和 ngx_http_upstream_module 模塊中的相關指令來完成當後端節點出現故障時,自動切換到下一個節點來提供訪問。

3.1 load-balance示例

upstream backend {
    ip_hash;
    server 172.29.88.226:8080 weight 2;
    server 172.29.88.226:8080 weight=1 max_fails=2 fail_timeout=30s ;
    server 172.29.88.227:8080 backup;
}
server {
    location / {
        proxy_pass http://backend;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    }
  • weight : 輪詢權值也是能夠用在ip_hash的,默認值爲1
  • max_fails : 容許請求失敗的次數,默認爲1。當超過最大次數時,返回proxy_next_upstream 模塊定義的錯誤。
  • fail_timeout : 有兩層含義,一是在 30s 時間內最多允許 2 次失敗;二是在經歷了 2 次失敗之後,30s時間內不分配請求到這臺服務器。
  • backup : 預留的備份機器。當其餘全部的非backup機器出現故障的時候,纔會請求backup機器,所以這臺機器的壓力最輕。(爲何個人1.6.3版本里配置backup啓動nginx時說invalid parameter "backup"?)
  • max_conns: 限制同時鏈接到某臺後端服務器的鏈接數,默認爲0即無限制。由於queue指令是commercial,因此仍是保持默認吧。

  • proxy_next_upstream : 這個指令屬於 http_proxy 模塊的,指定後端返回什麼樣的異常響應時,使用另外一個realserver

3.2 nginx_upstream_check_module

nginx_upstream_check_module 是專門提供負載均衡器內節點的健康檢查的外部模塊,由淘寶的姚偉斌大神開發,經過它能夠用來檢測後端 realserver 的健康狀態。若是後端 realserver 不可用,則後面的請求就不會轉發到該節點上,並持續檢查幾點的狀態。在淘寶本身的 tengine 上是自帶了該模塊。項目地址:https://github.com/yaoweibin/nginx_upstream_check_module

下面的是一個帶後端監控檢查的 nginx.conf 配置:

upstream backend {
    sticky;     # or simple round-robin
    server 172.29.88.226:8080 weight=2;
    server 172.29.88.226:8081 weight=1 max_fails=2 fail_timeout=30s ;
    server 172.29.88.227:8080 weight=1 max_fails=2 fail_timeout=30s ;
    server 172.29.88.227:8081;

    check interval=5000 rise=2 fall=3 timeout=1000 type=http;
    check_http_send "HEAD / HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
}
server {
    location / {
        proxy_pass http://backend;
    }
    location /status {
        check_status;
        access_log   off;
        allow 172.29.73.23;
        deny all;
    }

上面配置的意思是,對name這個負載均衡條目中的全部節點,每一個5秒檢測一次,請求2次正常則標記 realserver狀態爲up,若是檢測 3 次都失敗,則標記 realserver的狀態爲down,超時時間爲1秒。

check指令只能出如今upstream中:

  • interval : 向後端發送的健康檢查包的間隔。
  • fall : 若是連續失敗次數達到fall_count,服務器就被認爲是down。
  • rise : 若是連續成功次數達到rise_count,服務器就被認爲是up。
  • timeout : 後端健康請求的超時時間。
  • default_down : 設定初始時服務器的狀態,若是是true,就說明默認是down的,若是是false,就是up的。默認值是true,也就是一開始服務器認爲是不可用,要等健康檢查包達到必定成功次數之後纔會被認爲是健康的。
  • type:健康檢查包的類型,如今支持如下多種類型

    • tcp:簡單的tcp鏈接,若是鏈接成功,就說明後端正常。
    • http:發送HTTP請求,經過後端的回覆包的狀態來判斷後端是否存活。
    • ajp:向後端發送AJP協議的Cping包,經過接收Cpong包來判斷後端是否存活。
    • ssl_hello:發送一個初始的SSL hello包並接受服務器的SSL hello包。
    • mysql: 向mysql服務器鏈接,經過接收服務器的greeting包來判斷後端是否存活。
    • fastcgi:發送一個fastcgi請求,經過接受解析fastcgi響應來判斷後端是否存活
  • port: 指定後端服務器的檢查端口。你能夠指定不一樣於真實服務的後端服務器的端口,好比後端提供的是443端口的應用,你能夠去檢查80端口的狀態來判斷後端健康情況。默認是0,表示跟後端server提供真實服務的端口同樣。該選項出現於Tengine-1.4.0。

若是 type 爲 http ,你還可使用check_http_send來配置http監控檢查包發送的請求內容,爲了減小傳輸數據量,推薦採用 HEAD 方法。當採用長鏈接進行健康檢查時,需在該指令中添加keep-alive請求頭,如: HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n 。當採用 GET 方法的狀況下,請求uri的size不宜過大,確保能夠在1個interval內傳輸完成,不然會被健康檢查模塊視爲後端服務器或網絡異常。

check_http_expect_alive指定HTTP回覆的成功狀態,默認認爲 2XX 和 3XX 的狀態是健康的。

nginx-check-upstream

nginx-sticky-cookie.png

4. nginx的proxy緩存使用

nginx的頁面緩存功能與上面的負載均衡和健康檢查是沒有關係的,放在這裏一是由於懶得再起一篇文章,二是再有load-balance的地方通常都會啓用緩存的。

緩存也就是將js、css、image等靜態文件從tomcat緩存到nginx指定的緩存目錄下,既能夠減輕tomcat負擔,也能夠加快訪問速度,但這樣緩存及時清理成爲了一個問題,因此須要 ngx_cache_purge 這個模塊來在過時時間未到以前,手動清理緩存。(這裏有篇 文章,對比使用緩存、不使用緩存、使用動靜分離三種狀況下,高併發性能比較。使用代理緩存功能性能會高出不少倍)

http {
    ... // $upstream_cache_status記錄緩存命中率
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"'
                      '"$upstream_cache_status"';

    proxy_temp_path   /usr/local/nginx-1.6/proxy_temp;
    proxy_cache_path /usr/local/nginx-1.6/proxy_cache levels=1:2 keys_zone=cache_one:100m inactive=2d max_size=2g;

    server {
        listen       80; 
        server_name  ittest.example.com;
        root   html;
        index  index.html index.htm index.jsp;

        location ~ .*\.(gif|jpg|png|html|css|js|ico|swf|pdf)(.*) {
            proxy_pass  http://backend;
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header   X-Real-IP   $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;

            proxy_cache cache_one;
            add_header Nginx-Cache $upstream_cache_status;
            proxy_cache_valid  200 304 301 302 8h;
            proxy_cache_valid 404 1m;
            proxy_cache_valid  any 2d;
            proxy_cache_key $host$uri$is_args$args;
            expires 30d;
        }

        location ~ /purge(/.*) {
            #設置只容許指定的IP或IP段才能夠清除URL緩存。
            allow   127.0.0.1;
            allow   172.29.73.0/24;
            deny    all;
            proxy_cache_purge  cache_one $host$1$is_args$args;
            error_page 405 =200 /purge$1;
        }
    }
}

說明

  • proxy_temp_path : 緩存臨時目錄。後端的響應並不直接返回客戶端,而是先寫到一個臨時文件中,而後被rename一下當作緩存放在 proxy_cache_path 。0.8.9版本之後容許temp和cache兩個目錄在不一樣文件系統上(分區),然而爲了減小性能損失仍是建議把它們設成一個文件系統上。
  • proxy_cache_path ... : 設置緩存目錄,目錄裏的文件名是 cache_key 的MD5值。
    levels=1:2 keys_zone=cache_one:50m表示採用2級目錄結構,Web緩存區名稱爲cache_one,內存緩存空間大小爲100MB,這個緩衝zone能夠被屢次使用。文件系統上看到的緩存文件名相似於 /usr/local/nginx-1.6/proxy_cache/c/29/b7f54b2df7773722d382f4809d65029c
    inactive=2d max_size=2g表示2天沒有被訪問的內容自動清除,硬盤最大緩存空間爲2GB,超過這個大學將清除最近最少使用的數據。

  • proxy_cache : 引用前面定義的緩存區 cache_one

  • proxy_cache_key : 定義cache_key
  • proxy_cache_valid : 爲不一樣的響應狀態碼設置不一樣的緩存時間,好比200、302等正常結果能夠緩存的時間長點,而40四、500等緩存時間設置短一些,這個時間到了文件就會過時,而不管是否剛被訪問過。
  • expires : 在響應頭裏設置Expires:Cache-Control:max-age,返回給客戶端的瀏覽器緩存失效時間。

關於緩存的失效期限上面有三個選項:X-Accel-Expiresinactiveproxy_cache_validexpires,它們之間是有優先級的,按上面的順序若是在header裏設置 X-Accel-Expires 則它的優先級最高,不然inactive優先級最高。更多資料請參考 nginx緩存優先級這裏
nginx-cache-hit.png

清除緩存

上述配置的proxy_cache_purge指令用於方便的清除緩存,但必須按照第三方的 ngx_cache_purge 模塊才能使用,項目地址:https://github.com/FRiCKLE/ngx_cache_purge/

使用 ngx_cache_purge 模塊清除緩存有2種辦法(直接刪除緩存目錄下的文件也算一種辦法):

  1. echo發送PURGE指令
    proxy_cache_purge PURGE from 127.0.0.1表示只容許在來自本地的清除指令
# echo -e 'PURGE / HTTP/1.0\r\n' | nc 127.0.0.1 80
  1. GET方式請求URL
    即便用配置文件中的location ~ /purge(/.*),瀏覽器訪問http://ittest.example.com/purge/your/may/path來清除緩存,或者echo -e 'GET /purge/ HTTP/1.0\r\n' | nc ittest.example.com 80

nginx-cache-purge.png

參考


原文連接地址:http://seanlook.com/2015/06/02/nginx-cache-check/

相關文章
相關標籤/搜索