1. 程式人生 > >Web負載均衡高可用之Nginx+Keepalived

Web負載均衡高可用之Nginx+Keepalived

說明: 實驗環境CentOS_6.5-X86_64,由於前端Director上的操作有重複內容,因此下面的操作選擇在管理機上使用ansible以及安裝指令碼統一部署Director上的nginx&&keepalived,後端兩臺RealServer上的Nginx在此前的實驗中已經安裝好,直接可以提供服務,實驗過程中所有機器上的iptables&selinux均得關閉。管理機上ansible的配置,nginx詳細配置及其SysV init指令碼可查閱以前的博文,這裡不再贅述。
http://blog.csdn.net/celeste7777/article/details/49003873


http://blog.csdn.net/celeste7777/article/details/48678837
這裡寫圖片描述
這裡寫圖片描述
一、配置後端兩臺RealServer提供web server
1、在管理機上配置好realserver.sh,拷貝到RS1,RS2上並執行,繫結VIP到網路裝置lo:0,並修改相關核心引數來設定ARP抵制功能

[root@DQ ~]# ansible realserver -m copy -a 'src=/root/realserver.sh dest=/root/'
[root@DQ ~]# ansible realserver -m shell -a 'sh /root/realserver.sh start'

realserver.sh
這裡寫圖片描述
這裡寫圖片描述
可以將指令碼啟動命令新增至系統自啟檔案中,防止伺服器除錯時重啟而忘記引數設定
這裡寫圖片描述
2、測試web服務是否正常提供
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
二、在前端兩臺Director上安裝nginx
1、準備好編譯環境並安裝好依賴的基礎庫,新增執行nginx的使用者和組

[root@DQ ~]# ansible nginx -m yum -a "name=pcre-devel"
[root@DQ ~]# ansible nginx -m yum -a "name=openssl-devel"
[root@DQ ~]# ansible nginx -m group -a "system=yes name=nginx"
[root@DQ ~]# ansible nginx -m user -a "system=yes group=nginx name=nginx"

這裡寫圖片描述
2、在管理機上編輯安裝指令碼
這裡寫圖片描述
3、將安裝指令碼從管理機拷貝到節點機上,使用copy模組傳送檔案的時候報錯,是ansible需要python-selinux包而節點機上沒有,於是用yum模組安裝
這裡寫圖片描述
4、重新拷貝安裝指令碼到節點機;執行成功後為nginx提供SysV init腳
本,而後賦予此指令碼執行許可權,將其新增至服務管理列表,並設定開機自動啟動

[root@DQ ~]# ansible nginx -m copy -a 'src=/root/installNgx.sh dest=/root/'
[root@DQ ~]# ansible nginx -m shell -a 'sh /root/installNgx.sh'  
[root@DQ ~]# vim nginx  ##SysV init指令碼可檢視前一篇博文
[root@DQ ~]# ansible nginx -m copy -a 'src=/root/nginx dest=/etc/rc.d/init.d/nginx'
[root@DQ ~]# ansible nginx -m shell -a 'chmod +x /etc/rc.d/init.d/nginx'
[root@DQ ~]# ansible nginx -m shell -a 'chkconfig --add nginx'
[root@DQ ~]# ansible nginx -m shell -a 'chkconfig nginx on'

5、配置Nginx的upstream模組,實現對RealServer訪問的負載均衡,詳細說明可參考官方文件:
http://nginx.org/en/docs/http/load_balancing.html
http://nginx.org/en/docs/http/ngx_http_upstream_module.html
在前端兩臺Director上編輯nginx配置檔案/etc/nginx/nginx.conf,新增下圖紅框內容
這裡寫圖片描述
6、測試啟動nginx,訪問成功
這裡寫圖片描述
三、在前端兩臺Director上上安裝keepalived,讓其分別作為Web&Nginx的HA
1、管理機上編輯安裝指令碼,而後複製指令碼到Director並執行指令碼進行安裝
這裡寫圖片描述

[root@DQ ~]# ansible nginx -m copy -a 'src=/root/installKep.sh dest=/root/'
[root@DQ ~]# ansible nginx -m shell -a 'sh /root/installKep.sh'

2、管理機上編輯指令碼將keepalived做成服務模式,方便啟動和關閉,安裝成功後輸出命令到系統PAT路徑中,提供服務啟動指令碼和配置檔案
這裡寫圖片描述

[root@DQ ~]# ansible nginx -m copy -a 'src=/root/init.sh dest=/root/'
[root@DQ ~]# ansible nginx -m shell -a 'sh /root/init.sh'

3、安裝工具方便監測服務轉移情況

[root@DQ ~]# ansible nginx -m yum -a "name=ipvsadm"

4、在Director配置keepalived,先輸出keepalived的man手冊至man命令的查詢路徑,通過命令man keepalived.conf檢視配置選項幫助
這裡寫圖片描述
5、編輯配置檔案

[root@Node1 ~]# vim /etc/keepalived/keepalived.conf  
! Configuration File for keepalived
global_defs {
   notification_email {
   admin@localhost           ##出現故障向該郵箱傳送資訊,這裡可設為本機
   }

   notification_email_from keepalived@localhost     ##指定發件人
   smtp_server 127.0.0.1      ##指定smtp伺服器地址
   smtp_connect_timeout 30    ##指定smtp連線超時時間
   router_id LVS_DEVEL        ##執行keepalived的一個標識
}

vrrp_instance VI_1 {     ##VIP例項相當於虛擬路由
    state MASTER         ##當前節點的起始狀態,通常在master/slave的雙節點模型中,其一個預設為MASTER,而別一個預設為BACKUP
    interface eth0         ## 通告資訊基於該介面傳送以及虛擬路由的工作物理介面
    virtual_router_id 51      ## 兩臺伺服器必須一樣
    priority 99               ##priority為當關節點在當前虛擬路由器中的優先順序,MASTER的優先順序應該大於SLAVE
    advert_int 1            ##檢查間隔,1秒
    authentication {
        auth_type PASS     ## 認證方式為加密 
        auth_pass 1234      ## 加密的密碼,兩臺伺服器必須一樣(openssl rand -hex 6生成隨機字串)
    }
    virtual_ipaddress {
        10.33.100.11/16 dev eth0 label eth0:0
    }
virtual_server 10.33.100.11 80 {
    delay_loop 6     ##健康檢查時間間隔,單位秒
    lb_algo rr       ##負載排程演算法,支援的演算法:rr|wrr|lc|wlc|lblc|sh|dh
    lb_kind DR       ##LVS的型別:有NAT|DR|TUN
    nat_mask 255.255.255.0
    persistence_timeout50   ##會話保持時間,單位秒(可以適當延長時間以保持session)
    protocol TCP     ##轉發協議型別,有TCP和UDP兩種

    real_server 10.33.100.15 80 {
        weight 1
        HTTP_GET {
            url {
              path /
              status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
    real_server 10.33.100.16 80 {
        weight 1
        HTTP_GET {
            url {
              path /
              status_code 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

Node2上的配置檔案只需要做以下兩處修改即可,注意優先順序設定要做好規劃,一旦檢測到故障MASTER要降低優先順序,要確保降低以後的優先順序比BACKUP小
這裡寫圖片描述
6、編輯好配置檔案後就可以啟動keepalived服務測試負載均衡
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
不斷重新整理網頁測試負載均衡效果
這裡寫圖片描述
說明: RealServer的高可用功能實際上是由前端Director的健康狀況監測功能實現的,因此當其中一個RealServer故障時,並不會引起IP地址的漂移,而用ipvsadm -L -n命令檢視時會發現故障的RealServer條目已被刪除;當前端Director出現故障時則會引起IP地址的漂移。
至此Keepalived+Nginx的高可用叢集已部署完畢,接下來闡述測試高可用中的3個問題
Q1、當所有RealServer都故障停止服務,如何給使用者返回錯誤頁面?
當所有RealServer都down的時候,由Director本地提供錯誤頁面,而由於無法確定故障時刻真正工作的Director節點是哪一個,所以在前端兩臺Director上都要做圖中紅色標記的配置
方法1:利用niginx健康狀況監測功能
可以通過設定upstream模組的backup引數實現錯誤提示頁面的顯示
backup: 標記此處定義的server為備用機,當主節點不可用時備用機傳遞請求
marks the server as a backup server. It will be passed requests when the primary servers are unavailable.
這裡寫圖片描述
下面首先測試Director提供的錯誤頁面是否可以正常訪問
這裡寫圖片描述
在手動停止RealServer上的web服務,測試訪問
這裡寫圖片描述
方法2:利用keepalived健康狀況監測功能
將error_page指向/usr/html/errro.html, 由於後端RealServer停止服務,nginx轉發的請求無法得到響應,nginx會認為伺服器錯誤,會直接返回error_page
這裡寫圖片描述
編輯兩臺Director上keepalived的配置檔案/etc/keepalived/keepalived.conf ,在virtual_server中新增下圖示記的一行內容
這裡寫圖片描述

[root@DQ ~]# ansible nginx -m service -a 'name=keepalived state=restarted'

這裡寫圖片描述
3、手動停止RS1&&RS2上的web服務,測試錯誤提示頁面成功顯示;之後再手動啟動RS1&&RS2上的web服務,又可以正常訪問web頁面
這裡寫圖片描述
Q2、如何自寫監測指令碼監測Nginx程序,完成維護模式切換,實現真正意義上的負載均衡高可用?
1、編輯兩臺Director上keepalived的配置檔案/etc/keepalived/keepalived.conf ,在例項之外定義vrrp_script,例項中定義track_script來完成Nginx服務的監測
這裡寫圖片描述
2、編輯指令碼/usr/lib/nginx_pid.sh
這裡寫圖片描述
3、手動停止Director1上的nginx,而後重啟keepalived,測試keepalived能否實現主備節點切換

[root@Node1 ~]# service nginx stop
[root@DQ ~]# ansible nginx -m service -a 'name=keepalived state=restarted'

4、檢視日誌,切換成功
這裡寫圖片描述
Q3、如何在vrrp事務(主備節點切換,節點故障)發生時,傳送警告郵件給指定的管理員?
1、執行命令man keepalived.conf檢視啟用notify指令碼的定義,當節點狀態在主備間切換或失敗時,分別執行相對應的指令碼
這裡寫圖片描述
2、將配置檔案中需要3個指令碼實現的功能融合到一起,編寫notify指令碼,讓其可以接受選項引數來完成通知管理員事務的功能
-m, –mode {mm|mb}: 指定虛擬路由的模型,mm表示主主,mb表示主備;表示相對於同一種服務而言其VIP的工作型別;
-s, –service SERVICE,…: 指定服務指令碼名稱,當狀態切換時可自動啟動、重啟或關閉此服務;
-a, –address VIP: 指定相關虛擬路由器的VIP地址;
-n, –notify {master|backup|fault}: 指定通知的型別,即vrrp角色切換的目標角色;
-h, –help: 獲取指令碼的使用幫助;
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
3、編輯兩臺Director上keepalived的配置檔案/etc/keepalivedkeepalived.conf,在例項中新增下圖紅色標記部分,呼叫notify.sh指令碼:
這裡寫圖片描述
4、測試notify通知功能,在Node1上手動停止nginx服務,檢視郵件
這裡寫圖片描述
在手動啟動nginx,檢視郵件,至此notify測試完成,可以看出keepalived是在很大程度上依賴於執行指令碼來實現其擴充套件功能的HA服務
這裡寫圖片描述

附:Nginx配置
Nginx的程式碼是由一個核心和一系列的模組組成,核心主要用於提供WebServer的基本功能,以及Web和Mail反向代理的功能;還用於啟用網路協議,建立必要的執行時環境以及確保不同的模組之間平滑地進行互動。不過,大多跟協議相關的功能和某應用特有的功能都是由nginx的模組實現的。這些功能模組大致可以分為事件模組、階段性處理器、輸出過濾器、變數處理器、協議、upstream和負載均衡幾個類別,這些共同組成了nginx的http功能。事件模組主要用於提供OS獨立的(不同作業系統的事件機制有所不同)事件通知機制如kqueue或epoll等。協議模組則負責實現nginx通過http、tls/ssl、smtp、pop3以及imap與對應的客戶端建立會話。

Nginx的核心模組為Main和Events,此外還包括標準HTTP模組、可選HTTP模組和郵件模組,其還可以支援諸多第三方模組。Main用於配置錯誤日誌、程序及許可權等相關的引數,Events用於配置IO模型,如epoll、kqueue、select或poll等,它們是必備模組。

Nginx的主配置檔案由幾個段組成,這個段通常也被稱為nginx的上下文,每個段的定義格式如下所示。需要注意的是,其每一個指令都必須使用分號(;)結束,否則為語法錯誤。

<section> {
    <directive> <parameters>;
}

配置main模組

下面說明main模組中的幾個關鍵引數。

  • error_log:用於配置錯誤日誌,可用於main、http、server及location上下文中;

語法格式為:

error_log file | stderr [ debug | info | notice | warn | error | crit | alert | emerg ]

如果在編譯nginx時使用了–with-debug選項,還可以使用如下格式開啟除錯功能。

error_log LOGFILE [debug_core | debug_alloc | debug_mutex | debug_event | debug_http | debug_imap];

要禁用錯誤日誌,不能使用“error_log off;”,而要使用類似如下選項:

error_log /dev/null crit;
  • timer_resolution:用於降低gettimeofday()系統呼叫的次數。預設情況下,每次從kevent()、epoll、/dev/poll、select()或poll()返回時都會執行此係統呼叫。

語法格式為:

timer_resolution interval
例如:timer_resolution  100ms;
  • worker_cpu_affinity:通過sched_setaffinity()將worker繫結至CPU上,只能用於main上下文。

語法格式為:

worker_cpu_affinity cpumask ...
例如:
worker_processes     4;
worker_cpu_affinity 0001 0010 0100 1000;
  • worker_priority:為worker程序設定優先順序(指定nice值),此引數只能用於main上下文中,預設為0;

語法格式為:

worker_priority number
  • worker_processes:worker程序是單執行緒程序。如果Nginx用於CPU密集型的場景中,如SSL或gzip,且主機上的CPU個數至少有2個,那麼應該將此引數值設定為與CPU核心數相同;如果Nginx用於大量靜態檔案訪問的場景中,且所有檔案的總大小大於可用記憶體時,應該將此引數的值設定得足夠大以充分利用磁碟頻寬。此引數與Events上下文中的work_connections變數一起決定了maxclient的值:
  • maxclients = work_processes * work_connections

  • worker_rlimit_nofile:設定worker程序所能夠開啟的檔案描述符個數的最大值。

語法格式:

worker_rlimit_nofile number

配置Events模組

  • worker_connections:設定每個worker所處理的最大連線數,它與來自main上下文的worker_processes一起決定了maxclients的值。
  • max clients = worker_processes * worker_connections

而在反向代理場景中,其計算方法與上述公式不同,因為預設情況下瀏覽器將開啟2個連線,而nginx會為每一個連線開啟2個檔案描述符,因此,其maxclients的計算方法為:

  • max clients = worker_processes * worker_connections/4

  • use:在有著多於一個的事件模型IO的應用場景中,可以使用此指令設定nginx所使用的IO機制,預設為./configure指令碼選定的各機制中最適用當前OS的版本。

語法格式:

use [ kqueue | rtsig | epoll | /dev/poll | select | poll | eventport ]

一個配置示例

user nginx;
# the load is CPU-bound and we have 16 cores
worker_processes 16;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

events {
    use epoll;
    worker_connections 2048;
}

HTTP服務的相關配置

http上下文專用於配置用於http的各模組,此類指令非常的多,每個模組都有其專用指定,具體請引數nginx官方wiki關於模組部分的說明。大體上來講,這些模組所提供的配置指令還可以分為如下幾個類別。

  • 客戶端類指令

如client_body_buffer_size、client_header_buffer_size、client_header_timeout和keepalive_timeout等;

  • 檔案IO類指令

如aio、directio、open_file_cache、open_file_cache_min_uses、open_file_cache_valid和sendfile等;

  • hash類指令

用於定義Nginx為某特定的變數分配多大的記憶體空間,如types_hash_bucket_size、server_names_hash_bucket_size和variables_hash_bucket_size等;

  • 套接字類指令

用於定義Nginx如何處理tcp套接字相關的功能,如tcp_nodelay(用於keepalive功能啟用時)和tcp_nopush(用於sendfile啟用時)等;

虛擬伺服器相關配置

server {
    <directive> <parameters>;
}

用於定義虛擬伺服器相關的屬性,常見的指令有backlog、rcvbuf、bind及sndbuf等。

location相關的配置

location [modifier] uri {…} 或 location @name {…}

通常用於server上下文中,用於設定某URI的訪問屬性。location可以巢狀。

The prefix “@” specifies a named location. Such locations are not used during normal processing of requests, they are intended only to process internally redirected requests (see error_page, try_files). 如下面關於memcached的相關配置

server {
  location / {
    set $memcached_key $uri;
    memcached_pass     name:11211;
    default_type       text/html;
    error_page         404 @fallback;
  }

  location @fallback {
    proxy_pass http://backend;
  }
}

Nginx反向代理

Nginx通過proxy模組實現反向代理功能。在作為web反向代理伺服器時,nginx負責接收客戶請求,並能夠根據URI、客戶端引數或其它的處理邏輯將使用者請求排程至上游伺服器上(upstream server)。nginx在實現反向代理功能時的最重要指令為proxy_pass,它能夠將location定義的某URI代理至指定的上游伺服器(組)上。如下面的示例中,location的/uri將被替換為上游伺服器上的/newuri。

location /uri {
        proxy_pass http://www.magedu.com:8080/newuri;
    }

不過,這種處理機制中有兩個例外。一個是如果location的URI是通過模式匹配定義的,其URI將直接被傳遞至上游伺服器,而不能為其指定轉換的另一個URI。例如下面示例中的/forum將被代理為http://www.magedu.com/forum

location ~ ^/bbs {
        proxy_pass http://www.magedu.com;
    }

第二個例外是,如果在loation中使用的URL重定向,那麼nginx將使用重定向後的URI處理請求,而不再考慮上游伺服器上定義的URI。如下面所示的例子中,傳送給上游伺服器的URI為/index.php?page=,而不是/index。

location / {
        rewrite /(.*)$ /index.php?page=$1 break;
        proxy_pass http://localhost:8080/index;
    }

proxy模組的指令

proxy模組的可用配置指令非常多,它們分別用於定義proxy模組工作時的諸多屬性,如連線超時時長、代理時使用http協議版本等。下面對常用的指令做一個簡單說明。

proxy_connect_timeout: nginx將一個請求傳送至upstream server之前等待的最大時長;
proxy_cookie_domain:將upstream server通過Set-Cookie首部設定的domain屬性修改為指定的值,其值可以為一個字串、正則表示式的模式或一個引用的變數;
proxy_cookie_path: 將upstream server通過Set-Cookie首部設定的path屬性修改為指定的值,其值可以為一個字串、正則表示式的模式或一個引用的變數;
proxy_hide_header:設定傳送給客戶端的報文中需要隱藏的首部;
proxy_pass:指定將請求代理至upstream server的URL路徑;
proxy_set_header:將傳送至upsream server的報文的某首部進行重寫;
proxy_redirect:重寫location並重新整理從upstream server收到的報文的首部;
proxy_send_timeout:在連線斷開之前兩次傳送至upstream server的寫操作的最大間隔時長;
proxy_read_timeout:在連線斷開之前兩次從接收upstream server接收讀操作的最大間隔時長;

如下面的一個示例:

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;
    client_max_body_size 10m;
    client_body_buffer_size 128k;
    proxy_connect_timeout 30;
    proxy_send_timeout 15;
    proxy_read_timeout 15;

upstream模組

與proxy模組結合使用的模組中,最常用的當屬upstream模組。upstream模組可定義一個新的上下文,它包含了一組寶島upstream伺服器,這些伺服器可能被賦予了不同的權重、不同的型別甚至可以基於維護等原因被標記為down。

upstream模組常用的指令有:
ip_hash:基於客戶端IP地址完成請求的分發,它可以保證來自於同一個客戶端的請求始終被轉發至同一個upstream伺服器;
keepalive:每個worker程序為傳送到upstream伺服器的連線所快取的個數;
least_conn:最少連線排程演算法;
server:定義一個upstream伺服器的地址,還可包括一系列可選引數,如:

  • weight:權重;
  • fail_timeout:等待請求的目標伺服器傳送響應的時長;
  • down:手動標記其不再處理任何請求;
  • backup:用於fallback的目的,所有服務均故障時才啟動此伺服器;
  • max_fails:最大失敗連線次數,失敗連線的超時時長由fail_timeout指定;

例如:

upstream backend {
      server www.magedu.com weight=5;
      server www2.magedu.com:8080       max_fails=3  fail_timeout=30s;
    }

upstream模組的負載均衡演算法主要有三種,輪調(round-robin)、ip雜湊(ip_hash)和最少連線(least_conn)三種。

此外,upstream模組也能為非http類的應用實現負載均衡,如下面的示例定義了nginx為memcached服務實現負載均衡之目的。

upstream memcachesrvs {
    server 172.16.100.6:11211;
    server 172.16.100.7:11211;
}

server {
    location / {
    set $memcached_key "$uri?$args";
    memcached_pass memcachesrvs;
    error_page 404 = @fallback;
    }

    location @fallback {
         proxy_pass http://127.0.0.1:8080;
    }
}

if判斷語句

在location中使用if語句可以實現條件判斷,其通常有一個return語句,且一般與有著last或break標記的rewrite規則一同使用。但其也可以按需要使用在多種場景下,需要注意的是,不當的使用可能會導致不可預料的後果。

location / {
    if ($request_method == “PUT”) {
        proxy_pass http://upload.magedu.com:8080;
    } 

    if ($request_uri ~ "\.(jpg|gif|jpeg|png)$") {
        proxy_pass http://imageservers;
        break;
    }
}

upstream imageservers {
    server 172.16.100.8:80 weight 2;
    server 172.16.100.9:80 weight 3;
}

if語句中的判斷條件

正則表示式匹配:
~:與指定正則表示式模式匹配時返回“真”,判斷匹配與否時區分字元大小寫;
~*:與指定正則表示式模式匹配時返回“真”,判斷匹配與否時不區分字元大小寫;
!~:與指定正則表示式模式不匹配時返回“真”,判斷匹配與否時區分字元大小寫;
!~*:與指定正則表示式模式不匹配時返回“真”,判斷匹配與否時不區分字元大小寫;

檔案及目錄匹配判斷:
-f, !-f:判斷指定的路徑是否為存在且為檔案;
-d, !-d:判斷指定的路徑是否為存在且為目錄;
-e, !-e:判斷指定的路徑是否存在,檔案或目錄均可;
-x, !-x:判斷指定路徑的檔案是否存在且可執行;

nginx常用的全域性變數

下面是nginx常用的全域性變數中的一部分,它們經常用於if語句中實現條件判斷。

$args 
$content_length
$content_type 
$document_root 
$document_uri 
$host 
$http_user_agent 
$http_cookie 
$limit_rate 
$request_body_file 
$request_method 
$remote_addr 
$remote_port 
$remote_user 
$request_filename 
$request_uri 
$query_string 
$scheme
$server_protocol 
$server_addr 
$server_name 
$server_port 
$uri

反向代理效能優化

在反向代理場景中,nginx有一系列指令可用於定義其工作特性,如緩衝區大小等,給這些指令設定一個合理的值,可以有效提升其效能。

緩衝區設定

nginx在預設情況下在將其響應給客戶端之前會盡可能地接收來upstream伺服器的響應報文,它會將這些響應報文存暫存於本地並儘量一次性地響應給客戶端。然而,在來自於客戶端的請求或來自upsteam伺服器的響應過多時,nginx會試圖將之儲存於本地磁碟中,這將大大降低nginx的效能。因此,在有著更多可用記憶體的場景中,應該將用於暫存這些報文的緩衝區調大至一個合理的值。

  • proxy_buffer_size size:
    定用於暫存來自於upsteam伺服器的第一個響應報文的緩衝區大小;
  • proxy_buffering on|off:
    啟用緩衝upstream伺服器的響應報文,否則,如果proxy_max_temp_file_size指令的值為0,來自upstream伺服器的響應報文在接收到的那一刻將同步傳送至客戶端;一般情況下,啟用proxy_buffering並將proxy_max_temp_file_size設定為0能夠啟用快取響應報文的功能,並能夠避免將其快取至磁碟中;
  • proxy_buffers 8 4k|8k:
    用於緩衝來自upstream伺服器的響應報文的緩衝區大小;

快取

nginx做為反向代理時,能夠將來自upstream的響應快取至本地,並在後續的客戶端請求同樣內容時直接從本地構造響應報文。

  • proxy_cache zone|off:

定義一個用於快取的共享記憶體區域,其可被多個地方呼叫;快取將遵從upstream伺服器的響應報文首部中關於快取的設定,如 “Expires”、”Cache-Control: no-cache”、 “Cache-Control: max-age=XXX”、”private”和”no-store” 等,但nginx在快取時不會考慮響應報文的”Vary”首部。為了確保私有資訊不被快取,所有關於使用者的私有資訊可以upstream上通過”no-cache” or “max-age=0”來實現,也可在nginx設定proxy_cache_key必須包含使用者特有資料如$cookie_xxx的方式實現,但最後這種方式在公共快取上使用可能會有風險。因此,在響應報文中含有以下首部或指定標誌的報文將不會被快取。

Set-Cookie
    Cache-Control containing "no-cache", "no-store", "private", or a "max-age" with a non-numeric or 0 value
    Expires with a time in the past
    X-Accel-Expires: 0
  • proxy_cache_key:

設定在儲存及檢索快取時用於“鍵”的字串,可以使用變數為其值,但使用不當時有可能會為同一個內容快取多次;另外,將使用者私有資訊用於鍵可以避免將使用者的私有資訊返回給其它使用者;

  • proxy_cache_lock:

啟用此項,可在快取未命令中阻止多個相同的請求同時發往upstream,其生效範圍為worker級別;

  • proxy_cache_lock_timeout:proxy_cache_lock功能的鎖定時長;
  • proxy_cache_min_uses:某響應報文被快取之前至少應該被請求的次數;
  • proxy_cache_path:

定義一個用記儲存快取響應報文的目錄,及一個儲存快取物件的鍵及響應元資料的共享記憶體區域(keys_zone=name:size),其可選引數有:
levels:每級子目錄名稱的長度,有效值為1或2,每級之間使用冒號分隔,最多為3級;
inactive:非活動快取項從快取中剔除之前的最大快取時長;
max_size:快取空間大小的上限,當需要快取的物件超出此空間限定時,快取管理器將基於LRU演算法對其進行清理;
loader_files:快取載入器(cache_loader)的每次工作過程最多為多少個檔案載入元資料;
loader_sleep:快取載入器的每次迭代工作之後的睡眠時長;
loader_threashold:快取載入器的最大睡眠時長;
例如:

    proxy_cache_path  /data/nginx/cache/one    levels=1      keys_zone=one:10m;
    proxy_cache_path  /data/nginx/cache/two    levels=2:2    keys_zone=two:100m;
    proxy_cache_path  /data/nginx/cache/three  levels=1:1:2  keys_zone=three:1000m;
  • proxy_cache_use_stale:

在無法聯絡到upstream伺服器時的哪種情形下(如error、timeout或http_500等)讓nginx使用本地快取的過期的快取物件直接響應客戶端請求;其格式為:

  • proxy_cache_use_stale error | timeout | invalid_header | updating |http_500 | http_502 | http_503 | http_504 | http_404 | off proxy_cache_valid [ code …] time:

用於為不同的響應設定不同時長的有效快取時長,例如:proxy_cache_valid 200 302 10m;

  • proxy_cache_methods [GET HEAD POST]:

為哪些請求方法啟用快取功能;

  • proxy_cache_bypass string:

設定在哪種情形下,nginx將不從快取中取資料;例如:

proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;

使用示例

http {
    proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m
                                         inactive=24h  max_size=1g;
    server {
        location / {
            proxy_pass             http://www.magedu.com;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_valid      301 302 10m;
            proxy_cache_vaild      any 1m;
            proxy_cache_use_stale  error timeout invalid_header updating
                                   http_500 http_502 http_503 http_504;
        }
    }
}

壓縮

nginx將響應報文傳送至客戶端之前可以啟用壓縮功能,這能夠有效地節約頻寬,並提高響應至客戶端的速度。通常編譯nginx預設會附帶gzip壓縮的功能,因此,可以直接啟用之。

http {
    gzip on;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/json;
    gzip_disable msie6;
}

gzip_proxied指令可以定義對客戶端請求哪類物件啟用壓縮功能,如“expired”表示對由於使用了expire首部定義而無法快取的物件啟用壓縮功能,其它可接受的值還有“no-cache”、“no-store”、“private”、“no_last_modified”、
“no_etag”和“auth”等,而“off”則表示關閉壓縮功能。

配置示例
反向代理

server {
        listen       80;
        server_name  www.magedu.com;
        add_header X-Via $server_addr;  

        location / {
            root   html;
            index  index.html index.htm;
            if ($request_method ~* "PUT") {
                proxy_pass http://172.16.100.12;
                break;
            }
        }

        location /bbs {
            proxy_pass http://172.16.100.11/;
        }
} 

另外,add_header用於讓nginx在響應給使用者的報文中構造自定義首部,其使用格式為“add_header NAME VALUE”。

可以使用curl命令對配置好的服務進行請求,以驗正其效果。如:

# curl -I http://www.magedu.com/bbs/
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Tue, 14 May 2013 10:19:10 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 15
Connection: keep-alive
Last-Modified: Tue, 30 Apr 2013 09:34:09 GMT
ETag: "186e9f-f-b4076640"
X-Via: 172.16.100.107
Accept-Ranges: bytes

在後端伺服器172.16.100.12上裝載dav模組,並開放其dav功能,而後驗正檔案上傳效果。開放dav功能的方法如下:

首先啟用如下兩個模組:

LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

而後配置相應主機的目錄如下所示,關鍵是其中的dav一行。

<Directory "/var/www/html">
    dav on
    Options Indexes FollowSymLinks
    Order allow,deny
    Allow from all
</Directory>

接著嘗試訪問代理伺服器:

# curl -I -T /etc/inittab http://www.magedu.com/

啟用快取
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;

proxy_cache_path /nginx/cache/first  levels=1:2   keys_zone=first:10m max_size=512m;

server {
    listen       80;
    server_name  www.magedu.com;

    location / {
        root   html;
        index  index.html index.htm;
        if ($request_method ~* "PUT") {
            proxy_pass http://172.16.100.12;
            break;
        }
    }

    location /bbs {
        proxy_pass http://172.16.100.11/;
        proxy_cache first;
        proxy_cache_valid 200 1d;
        proxy_cache_valid 301 302 10m;
        proxy_cache_valid any 1m;
    }
} 

}

使用upstream
不啟用快取

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream websrv {
        server 172.16.100.11 weight=1;
        server 172.16.100.12 weight=1;
        server 127.0.0.1:8080 backup;
    }
    server {
        listen       80;
        server_name  www.magedu.com;

        add_header X-Via $server_addr;

        location / {
            proxy_pass http://websrv;
            index  index.html index.htm;

            if ($request_method ~* "PUT") {
                proxy_pass http://172.16.100.12;
                break;
            }
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    server {
        listen 8080;
        server_name localhost;
        root /nginx/htdocs;
        index index.html;
    }
}

測試效果:預設情況下,nginx對定義了權重的upstream伺服器使用加權輪調的方法排程訪問,因此,其多次訪問應該由不同的伺服器進行響應。如下所示。

# curl  http://172.16.100.107/
RS2.magedu.com

# curl  http://172.16.100.107/
RS1.magedu.com

根據上面的配置,如果172.16.100.11和172.16.100.12兩個upstream伺服器均宕機時,將由本地監聽在8080埠的虛擬主機進行響應。

# curl  http://172.16.100.107/
Sorry...

為upstream啟用快取

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    proxy_cache_path /nginx/cache/first  levels=1:2   keys_zone=first:10m max_size=512m;

    upstream websrv {
        server 172.16.100.11 weight=1;
        server 172.16.100.12 weight=1;
        server 127.0.0.1:8080 backup;
    }
    server {
        listen       80;
        server_name  www.magedu.com;

        add_header X-Via $server_addr;
        add_header X-Cache-Status $upstream_cache_status;

        location / {
            proxy_pass http://websrv;
            proxy_cache first;
            proxy_cache_valid 200 1d;
            proxy_cache_valid 301 302 10m;
            proxy_cache_valid any 1m;
            index  index.html index.htm;

            if ($request_method ~* "PUT") {
                proxy_pass http://172.16.100.12;
                break;
            }
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    server {
        listen 8080;
        server_name localhost;
        root /nginx/htdocs;
        index index.html;
    }
}

第一次訪問某可快取資源時,在本地快取中尚未有其對應的快取物件,因此,其一定為未命中狀態。而第二次請求時,則可以直接從本地快取構建響應報文。

# curl -I http://www.magedu.com/
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Tue, 14 May 2013 10:53:07 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 15
Connection: keep-alive
Last-Modified: Tue, 30 Apr 2013 09:34:09 GMT
ETag: "186e9f-f-b4076640"
Accept-Ranges: bytes
X-Via: 172.16.100.107
X-Cache-Status: MISS

# curl -I http://www.magedu.com/
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Tue, 14 May 2013 10:53:09 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 15
Connection: keep-alive
Last-Modified: Tue, 30 Apr 2013 09:34:09 GMT
ETag: "186e9f-f-b4076640"
X-Via: 172.16.100.107
X-Cache-Status: HIT
Accept-Ranges: bytes