1. 程式人生 > >nginx教程第八篇:用HTTP proxy module配置一個反向代理伺服器

nginx教程第八篇:用HTTP proxy module配置一個反向代理伺服器

反向代理( reverse proxy) 方式是指用代理伺服器來接受Internet上的連線請求, 然後將 請求轉發給內部網路中的上游伺服器, 並將從上游伺服器上得到的結果返回給Internet上請求 連線的客戶端, 此時代理伺服器對外的表現就是一個Web伺服器。 充當反向代理伺服器也是 Nginx的一種常見用法( 反向代理伺服器必須能夠處理大量併發請求) , 本文將介紹Nginx作 為HTTP反向代理伺服器的基本用法。 由於Nginx具有“強悍”的高併發高負載能力, 因此一般會作為前端的伺服器直接向客戶 端提供靜態檔案服務。 但也有一些複雜、 多變的業務不適合放到Nginx伺服器上, 這時會用 Apache、 Tomcat等伺服器來處理。 於是, Nginx通常會被配置為既是靜態Web伺服器也是反向 代理伺服器

( 如 下圖 所示) , 不適合Nginx處理的請求就會直接轉發到上游伺服器中處理。 這裡寫圖片描述

與Squid等其他反向代理伺服器相比, Nginx的反向代理功能有自己的特點, 如 下圖 所 示: 這裡寫圖片描述 當客戶端發來HTTP請求時, Nginx並不會立刻轉發到上游伺服器, 而是先把使用者的請求 ( 包括HTTP包體) 完整地接收到Nginx所在伺服器的硬碟或者記憶體中, 然後再向上游伺服器 發起連線, 把快取的客戶端請求轉發到上游伺服器。 而Squid等代理伺服器則採用一邊接收 客戶端請求, 一邊轉發到上游伺服器的方式。 Nginx的這種工作方式有什麼優缺點呢? 很明顯, 缺點是延長了一個請求的處理時間, 並增加了用於快取請求內容的記憶體和磁碟空間。 而優點則是降低了上游伺服器的負載, 儘量 把壓力放在Nginx伺服器上。

Nginx的這種工作方式為什麼會降低上游伺服器的負載呢? 通常, 客戶端與代理伺服器 之間的網路環境會比較複雜, 多半是“走”公網, 網速平均下來可能較慢, 因此, 一個請求可 能要持續很久才能完成。 而代理伺服器與上游伺服器之間一般是“走”內網, 或者有專線連 接, 傳輸速度較快。 Squid等反向代理伺服器在與客戶端建立連線且還沒有開始接收HTTP包 體時, 就已經向上遊伺服器建立了連線。 例如, 某個請求要上傳一個1GB的檔案, 那麼每次 Squid在收到一個TCP分包( 如2KB) 時, 就會即時地向上遊伺服器轉發。 在接收客戶端完整 HTTP包體的漫長過程中, 上游伺服器始終要維持這個連線, 這直接對上游伺服器的併發處 理能力提出了挑戰。 Nginx則不然, 它在接收到完整的客戶端請求( 如1GB的檔案) 後, 才會與上游伺服器 建立連線轉發請求, 由於是內網, 所以這個轉發過程會執行得很快。 這樣, 一個客戶端請求 佔用上游伺服器的連線時間就會非常短, 也就是說, Nginx的這種反向代理方案主要是為了 降低上游伺服器的併發壓力。 Nginx將上游伺服器的響應轉發到客戶端有許多種方法。

負載均衡的基本配置

作為代理伺服器, 一般都需要向上遊伺服器的叢集轉發請求。 這裡的負載均衡是指選擇 一種策略, 儘量把請求平均地分佈到每一臺上游伺服器上。 下面介紹負載均衡的配置項:

1. upstream塊
語法: upstream name{...}
配置塊: http

upstream塊定義了一個上游伺服器的叢集, 便於反向代理中的proxy_pass使用。 例如:

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
} 

server {
    location / {
        proxy_pass http://backend;
    }
}
2. server
語法: server name[parameters];
配置塊: upstream

server配置項指定了一臺上游伺服器的名字, 這個名字可以是域名、 IP地址埠、 UNIX 控制代碼等, 在其後還可以跟下列引數:

· weight=number: 設定向這臺上遊伺服器轉發的權重, 預設為1。
· max_fails=number: 該選項與fail_timeout配合使用, 指在fail_timeout時間段內, 如果向
當前的上游伺服器轉發失敗次數超過number, 則認為在當前的fail_timeout時間段內這臺上遊
伺服器不可用。 max_fails預設為1, 如果設定為0, 則表示不檢查失敗次數。
· fail_timeout=time: fail_timeout表示該時間段內轉發失敗多少次後就認為上游伺服器暫
時不可用, 用於優化反向代理功能。 它與向上遊伺服器建立連線的超時時間、 讀取上游服務
器的響應超時時間等完全無關。 fail_timeout預設為10秒。
· down: 表示所在的上游伺服器永久下線, 只在使用ip_hash配置項時才有用。
· backup: 在使用ip_hash配置項時它是無效的。 它表示所在的上游伺服器只是備份服務
器, 只有在所有的非備份上游伺服器都失效後, 才會向所在的上游伺服器轉發請求。
例如:
upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;
}
3. ip_hash
語法: ip_hash;
配置塊: upstream

在有些場景下, 我們可能會希望來自某一個使用者的請求始終落到固定的一臺上游伺服器 中。 例如, 假設上游伺服器會快取一些資訊, 如果同一個使用者的請求任意地轉發到叢集中的 任一臺上游伺服器中, 那麼每一臺上游伺服器都有可能會快取同一份資訊, 這既會造成資源 的浪費, 也會難以有效地管理快取資訊。 ip_hash就是用以解決上述問題的, 它首先根據客戶 端的IP地址計算出一個key, 將key按照upstream叢集裡的上游伺服器數量進行取模, 然後以取 模後的結果把請求轉發到相應的上游伺服器中。 這樣就確保了同一個客戶端的請求只會轉發 到指定的上游伺服器中。 注意:

  1. ip_hash與weight(權重) 配置不可同時使用;
  2. 如果upstream叢集中有一臺上游伺服器暫時不可用, 不能直接刪除該配置, 而是要down引數標識, 確保轉發策略的一貫性;
  3. backup: 在使用ip_hash配置項時它是無效的。 它表示所在的上游伺服器只是備份服務 器, 只有在所有的非備份上游伺服器都失效後, 才會向所在的上游伺服器轉發請求。

例如:

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
    server backend4.example.com;
}
4. 記錄日誌時支援的變數

如果需要將負載均衡時的一些資訊記錄到access_log日誌中, 那麼在定義日誌格式時可 以使用負載均衡功能提供的變數, 如下表 ( 訪問上游伺服器時可以使用的變數 ):

變數名 意義
$upstream_addr 處理請求的上游伺服器地址
$upstream_cache_status 標識是否命中快取,取值範圍:MISS、EXPIRED、UPDATEING、STALE、HIT
$upstream_status 上游伺服器返回相應的HTTP響應嗎
$upstream_response_time 上游伺服器的響應時間,精度到毫秒
$upstream_http_$HEADER HTTP的頭部,如 upstream_http_host

例如:

可以在定義access_log訪問日誌格式時使用上表中的變數。
log_format timing '$remote_addr - $remote_user [$time_local] $request '
'upstream_response_time $upstream_response_time '
'msec $msec request_time $request_time';

log_format up_head '$remote_addr - $remote_user [$time_local] $request '
'upstream_http_content_type $upstream_http_content_type';

反向代理的基本配置

下面介紹反向代理的基本配置項:

1. proxy_pass
語法: proxy_pass URL;
配置塊: location、 if

此配置項將當前請求反向代理到URL引數指定的伺服器上, URL可以是主機名或IP地址 加埠的形式, 例如:

proxy_pass http://localhost:8000/uri/;

也可以是UNIX控制代碼:

proxy_pass http://unix:/path/to/backend.socket:/uri/;

還可以如上節負載均衡中所示, 直接使用upstream塊, 例如:

upstream backend {
    …
} 

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

使用者可以把HTTP轉換成更安全的HTTPS, 例如:

proxy_pass https://192.168.0.1;

預設情況下反向代理是不會轉發請求中的Host頭部的。 如果需要轉發, 那麼必須加上配 置:

proxy_set_header Host $host;
2. proxy_method
語法: proxy_method method;
配置塊: http、 server、 location

此配置項表示轉發時的協議方法名。 例如設定為:
proxy_method POST;

那麼客戶端發來的GET請求在轉發時方法名也會改為POST。

3. proxy_hide_header
語法: proxy_hide_header the_header;
配置塊: http、 server、 location

Nginx會將上游伺服器的響應轉發給客戶端, 但預設不會轉發以下HTTP頭部欄位: Date、 Server、 X-Pad和X-Accel-*。 使用proxy_hide_header後可以任意地指定哪些HTTP頭部 欄位不能被轉發。 例如:

proxy_hide_header Cache-Control;
proxy_hide_header MicrosoftOfficeWebServer;
4. proxy_pass_header
語法: proxy_pass_header the_header;
配置塊: http、 server、 location

與proxy_hide_header功能相反, proxy_pass_header會將原來禁止轉發的header設定為允許 轉發。

5. proxy_pass_request_body
語法: proxy_pass_request_body on|off;
預設: proxy_pass_request_body on;
配置塊: http、 server、 location

作用為確定是否向上遊伺服器傳送HTTP包體部分。

6. proxy_pass_request_headers
語法: proxy_pass_request_headers on|off;
預設: proxy_pass_request_headers on;
配置塊: http、 server、 location

作用為確定是否轉發HTTP頭部。

7. proxy_redirect
語法: proxy_redirect [default|off|redirect replacement];
預設: proxy_redirect default;
配置塊: http、 server、 location

當上遊伺服器返回的響應是重定向或重新整理請求(如HTTP響應碼是301或者302)時,
proxy_redirect可以重設HTTP頭部的location或refresh欄位。 例如, 
如果上游伺服器發出的響應是302重定向請求, location欄位的URI是http://localhost:8000/two/some/uri/ ,
那麼在下面的配置情況下, 實際轉發給客戶端的location是http://frontendone/some/uri/ 。
    proxy_redirect http://localhost:8000/two/
    http://frontendone;
    
這裡還可以使用ngx-http-core-module提供的變數來設定新的location欄位。 例如:
    proxy_redirect http://localhost:8000/
    http://$host:$server_port/;
    
也可以省略replacement引數中的主機名部分, 這時會用虛擬主機名稱來填充。 例如:
    proxy_redirect http://localhost:8000/two/one;
    
使用off引數時, 將使location或者refresh欄位維持不變。 例如:
    proxy_redirect off;
    
使用預設的default引數時, 會按照proxy_pass配置項和所屬的location配置項重組發往客
戶端的location頭部。 例如, 下面兩種配置效果是一樣的:
location one {
    proxy_pass http://upstream:port/two/;
    proxy_redirect default;
}

location one {
    proxy_pass http://upstream:port/two/;
    proxy_redirect http://upstream:port/two/one;
}
8. proxy_next_upstream
語法:proxy_next_upstream [error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off];
預設: proxy_next_upstream error timeout;
配置塊: http、 server、 location

此配置項表示當向一臺上游伺服器轉發請求出現錯誤時, 繼續換一臺上游伺服器處理這 個請求。 前面已經說過, 上游伺服器一旦開始傳送應答, Nginx反向代理伺服器會立刻把應 答包轉發給客戶端。 因此, 一旦Nginx開始向客戶端傳送響應包, 之後的過程中若出現錯誤 也是不允許換下一臺上游伺服器繼續處理的。 這很好理解, 這樣才可以更好地保證客戶端只 收到來自一個上游伺服器的應答。 proxy_next_upstream的引數用來說明在哪些情況下會繼續 選擇下一臺上游伺服器轉發請求。 ·error: 當向上遊伺服器發起連線、 傳送請求、 讀取響應時出錯。 ·timeout: 傳送請求或讀取響應時發生超時。 ·invalid_header: 上游伺服器傳送的響應是不合法的。 ·http_500: 上游伺服器返回的HTTP響應碼是500。 ·http_502: 上游伺服器返回的HTTP響應碼是502。 ·http_503: 上游伺服器返回的HTTP響應碼是503。 ·http_504: 上游伺服器返回的HTTP響應碼是504。 ·http_404: 上游伺服器返回的HTTP響應碼是404。 ·off: 關閉proxy_next_upstream功能—出錯就選擇另一臺上游伺服器再次轉發。 Nginx的反向代理模組還提供了很多種配置, 如設定連線的超時時間、 臨時檔案如何存 儲, 以及最重要的如何快取上游伺服器響應等功能。 這些配置可以通過閱讀 ngx_http_proxy_module模組的說明了解, 只有深入地理解, 才能實現一個高效能的反向代理 伺服器。