1. 程式人生 > >架構設計:負載均衡層設計方案(3)——Nginx進階

架構設計:負載均衡層設計方案(3)——Nginx進階

上篇文章《架構設計:負載均衡層設計方案(2)——Nginx安裝》(http://blog.csdn.net/yinwenjie/article/details/46620711),我們介紹了Nginx的核心設計思想、基本安裝和使用。本來準備繼續介紹Nginx的幾個使用特性,但是奈何博文篇幅太長,只有將一篇文章拆成兩篇。本文我們將承接上文,繼續講解Nginx的實用特性,包括gzip功能、rewirte功能和一個第三方的節點監測模組。本文我們還將提到Taobao團隊對Nginx的深度改造Tengine。
1、Nginx繼續進階
1.1、gzip

nginx對返回給瀏覽器的http response body是可以進行壓縮的。雖然需要消耗一點cpu和記憶體資源,但是想到100KB的資料量可以壓縮到60KB甚至更小進行傳輸,是否有一定的吸引力?這裡我的建議是,不要為了節約成本將業務服務和負載層服務放在一臺物理伺服器上,這樣做既影響效能又增加了運維難度。http返回資料進行壓縮的功能在很多場景下都實用:

如果瀏覽器使用的是3G/4G網路,那麼流量對於使用者來說就是money。

壓縮可節約伺服器機房的對外頻寬,為更多使用者服務。按照目前的市場價良好的機房頻寬資源的一般在200RMB/Mbps,而伺服器方案的壓力往往也來自於機房頻寬。

主要注意的是,不是Nginx開啟了gzip功能,HTTP響應的資料就一定會被壓縮,除了滿足Nginx設定的“需要壓縮的http格式”以外,客戶端(瀏覽器)也需要支援gzip(不然它怎麼解壓呢),一個好訊息是,目前大多數瀏覽器和API都支援http壓縮。

我們首先來講解Nginx中的gzip的設定引數,然後我們講解當開啟壓縮功能後,HTTP的互動過程和過程中關鍵的幾個屬性。我們首先來看看Nginx中開啟gzip的屬性(gzip的設定放置在HTTP主配置區域):

#開啟gzip壓縮服務, 
gzip on;

#gzip壓縮是要申請臨時記憶體空間的,假設前提是壓縮後大小是小於等於壓縮前的。例如,如果原始檔案大小為10K,那麼它超過了8K,所以分配的記憶體是8 * 2 = 16K;再例如,原始檔案大小為18K,很明顯16K也是不夠的,那麼按照 8 * 2 * 2 = 32K的大小申請記憶體。如果沒有設定,預設值是申請跟原始資料相同大小的記憶體空間去儲存gzip壓縮結果。 
gzip_buffers 2 8k;

#進行壓縮的原始檔案的最小大小值,也就是說如果原始檔案小於5K,那麼就不會進行壓縮了 
gzip_min_length 5K;

#gzip壓縮基於的http協議版本,預設就是HTTP 1.1 
gzip_http_version 1.1; # gzip壓縮級別1-9,級別越高壓縮率越大,壓縮時間也就越長CPU越高 gzip_comp_level 5; #需要進行gzip壓縮的Content-Type的Header的型別。建議js、text、css、xml、json都要進行壓縮;圖片就沒必要了,gif、jpge檔案已經壓縮得很好了,就算再壓,效果也不好,而且還耗費cpu。 gzip_types text/HTML text/plain application/x-JavaScript text/css application/xml;

設定完成後,重啟nginx,即可生效。下面我們來看看瀏覽器和伺服器進行gzip壓縮的請求和處理返回過程(實際上在我的《標準Web系統的架構分層》文章中,已經有所提及):
這裡寫圖片描述

當開啟HTTP的gzip功能時,客戶端發出http請求時,會通過headers中的Accept-Encoding屬性告訴伺服器“我支援gzip解壓,解壓格式(演算法)deflate,sdch為:”。Accept-Encoding:gzip,deflate,sdch

注意,不是request說自己支援解壓,Nginx返回response資料的時候就一定會壓縮。這還要看本次Nginx返回資料的格式是什麼,如果返回資料的原始資料格式,和設定的gzip_types相符合,這時Nginx才會進行壓縮。

Nginx返回response headers是,如果資料被壓縮了,就會在Content-Encoding屬性中標示gzip,表示接下來返回的response content是經過壓縮的;並且在Content-Type屬性中表示資料的原始格式。

最後返回經過壓縮的response content給客戶端,客戶端再進行解壓。這裡注意一下,在客戶端傳送的headers裡面,有一個deflate,sdch。這是兩種壓縮演算法,如果讀者感興趣,可以查查相關的資料(我建議查查,瞭解哈弗曼壓縮演算法對擴充套件自己的架構思路很有幫助)

本小結內容,假定讀者瞭解正則表示式。如果您不清楚正則表示式,請首先Google或者百度,正則表示式不在我們討論的範圍內。

Nginx的強大在於其對URL請求的重寫(重定位)。Nginx的rewrite功能依賴於PCRE Lib,請一定在Nginx編譯安裝時,安裝Pcre lib。請參見我的上一篇文章《架構設計:負載均衡層設計方案(2)——Nginx安裝》

我們先從講解rewrite的關鍵語法,然後出示幾個示例,由示例進行講解。先來說一下Nginx中幾個關鍵的語法:
正在表示式匹配:

~ 區分大小寫進行正則表示式匹配
~* 不區分大小寫進行正則表示式匹配
!~ 區分大小寫進行正則表示式不匹配
!~* 不區分大小寫進行正則表示式不匹配

舉例說明:

示例1:location ~* .(jpg|gif|png|ioc|jpeg)$

location是Nginx中的關鍵字,代表當前的URL請求值。
以上表達式表示對URL進行不區分大小寫的匹配,一旦URL以jpg或gif或png或ioc或jpeg結尾時,匹配成功。

示例2:var1(\d+)

var1是Nginx中使用set關鍵字定義的變數,以上語句代表var1和一個整數進行匹配。
Nginx中的全域性變數:
從上面的各個例項中,我們已經發現Nginx是支援變數的,Nginx還內建了一些全域性變數,這裡列舉一些比較重要的全域性變數:

contentlength:requestheaderContentLengthcontent_type: 獲取request中header部分的“Content_type”值。
requestmethod:POSTGETremote_addr: 傳送請求的客戶端ip
remoteport:request_uri: 含有引數的完整的初始URI
serveraddr:requestserveripserver_port: 請求到達的伺服器的埠號。

rewrite語法

rewrite regex replacement flag

#regex:表示當前匹配的正則表示式。只有$url大小寫相關匹配regex正則表示式,這個$url才會被rewrite進行重定向。

#replacement:重定向目標規則。這個目標規則支援動態變數繫結,這個問題下文馬上用示例來講。

#flag:重定向規則

rewrite中的Flag關鍵字

redirect:通知客戶端重定向到rewrtie後面的地址。
permanent:通知客戶端永久重定向到rewrtie後面的地址。
last:將rewrite後的地址重新在server標籤執行。
break:將rewrite後地址重新在當前的location標籤執行。

實際上針對客戶端來說,其效果是一樣的,都是由客戶端重新發起http請求,請求地址重新定位到replacement規則的URL地址;這裡關鍵要講解最常用的last和break兩個關鍵字:

所有的rewrite語句都是要在server中的location中書寫的,如下:
server {
。。。。。。
。。。。。。
location … {
if(…) {
rewirte regex replacement flag;
}
rewirte regex replacement flag;
}
}

那麼,break關鍵字說明重寫的replacement地址在當前location的區域馬上執行。
last關鍵字說明重寫的replacement地址在當前server所有的location中重新再做匹配。
下面我們結合rewrite關鍵字和rewrite flag關鍵字給出典型的示例進行講解:

示例1:
location ~* ^/(.+)/(.+).(jpg|gif|png|jpeg){  
    rewrite ^/orderinfo/(.+).(jpg|gif|png|jpeg)
/img/1.2 break;
root /cephclient;
}

location在不進行大小寫區分的情況下利用正則表示式對urlrewriterewriteurlregex1,regex表示式第二個括號中的內容對應$2,以此類推。
這樣重定位的意義就很明確了:將任何目錄下的檔名重定位到img目錄下的對應檔名,
並且馬上在這個location中(注意是Nginx,而不是客戶端)執行這個重寫後的URL定位。

示例2:
server {
。。。。
。。。。
location ~* ^/orderinfo/(.+).(jpg|gif|png|jpeg){  
        rewrite ^/orderinfo/(.+).(.+)
/img/1.2 last;
}

location / {
    root   /cephclient;
}

}

在server中,有兩個location位置,當url需要訪問orderinfo目錄下的某一個圖片時,rewrite將重寫這個url,
並且重新帶入這個url到server執行,這樣“location /”這個location就會執行了,並找到圖片儲存的目錄。

1.3、健康檢查模組
在本小節我們介紹一個用於Nginx對後端UpStream叢集節點健康狀態檢查的第三方模組:nginx_upstream_check_module(https://github.com/yaoweibin/nginx_upstream_check_module)。這個模組有資料介紹是TaoBao團隊開發的,但是我在GitHua上試圖求證時並沒有找到直接證據。

這裡需要說明的是,目前有很多Nginx模組實現Nginx對後端叢集節點的健康監測,不止nginx_upstream_check_module。Nginx官方有一個模組healthcheck_nginx_upstreams也可以實現對後端節點的健康監測(https://github.com/cep21/healthcheck_nginx_upstreams有詳細的安裝和使用介紹)

我們回到對nginx_upstream_check_module的講解,要使用這個第三方模組首先您需要進行下載,然後通過patch命令將補丁打入您原有的Nginx原始碼中,並且重新進行編譯安裝。下面我們來重點講解一下這個模組的安裝和使用。
下載nginx_upstream_check_module模組:

wget https://codeload.github.com/yaoweibin/nginx_upstream_check_module/zip/master

您也可以直接到GitHua上進行下載,還一個在linux系統上使用git命令進行下載。

解壓安裝,並補丁打入Nginx原始碼

# unzip ./nginx_upstream_check_module-master.zip

注意是將補丁打入Nginx原始碼,不是Nginx的安裝路徑:

# cd ./nginx-1.6.2

# patch -p1 < ../nginx_upstream_check_module-master/check_1.5.12+.patch

如果補丁安裝成功,您將看到以下的提示資訊:
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

這裡請注意:在nginx_upstream_check_module官網的安裝說明中,有一個打補丁的注意事項:
If you use nginx-1.2.1 or nginx-1.3.0, the nginx upstream round robin
module changed greatly. You should use the patch named
'check_1.2.1.patch'.
If you use nginx-1.2.2+ or nginx-1.3.1+, It added the upstream
least_conn module. You should use the patch named 'check_1.2.2+.patch'.
If you use nginx-1.2.6+ or nginx-1.3.9+, It adjusted the round robin
module. You should use the patch named 'check_1.2.6+.patch'.
If you use nginx-1.5.12+, You should use the patch named
'check_1.5.12+.patch'.
If you use nginx-1.7.2+, You should use the patch named
'check_1.7.2+.patch'.

這裡我們的Nginx的版本是1.6.2,那麼就應該打入check_1.5.12+.patch這個補丁

重新編譯安裝Nginx:

注意重新編譯Nginx,要使用add-module引數將這個第三方模組安裝進去:

# ./configure --prefix=/usr/nginx-1.6.2/ --add-module=../nginx_upstream_check_module-master/

# make && make install
通過以上的步驟,第三方的nginx_upstream_check_module模組就在Nginx中準備好了。接下來我們講解一下如何使用這個模組。首先看一下upstream的配置資訊:

upstream cluster {
    # simple round-robin
    server 192.168.0.1:80;
    server 192.168.0.2:80;

    check interval=5000 rise=1 fall=3 timeout=4000;

    #check interval=3000 rise=2 fall=5 timeout=1000 type=ssl_hello;
    #check interval=3000 rise=2 fall=5 timeout=1000 type=http;
    #check_http_send "HEAD / HTTP/1.0\r\n\r\n";
    #check_http_expect_alive http_2xx http_3xx;
}

上面的程式碼中,check部分就是呼叫nginx_upstream_check_module模組的語法:
check interval=milliseconds [fall=count] [rise=count]
[timeout=milliseconds] [default_down=true|false]
[type=tcp|http|ssl_hello|mysql|ajp|fastcgi]
interval:必要引數,檢查請求的間隔時間。

fall:當檢查失敗次數超過了fall,這個服務節點就變成down狀態。

rise:當檢查成功的次數超過了rise,這個服務節點又會變成up狀態。

timeout:請求超時時間,超過等待時間後,這次檢查就算失敗。

default_down:後端伺服器的初始狀態。預設情況下,檢查功能在Nginx啟動的時候將會把所有後端節點的狀態置為down,檢查成功後,在置為up。

type:這是檢查通訊的協議型別,預設為http。以上型別是檢查功能所支援的所有協議型別。

check_http_send http_packet

http_packet的預設格式為:”GET / HTTP/1.0\r\n\r\n”
check_http_send設定,這個設定描述了檢查模組在每次檢查時,向後端節點發送什麼樣的資訊

check_http_expect_alive [ http_2xx | http_3xx | http_4xx | http_5xx ]
這些狀態程式碼表示伺服器的HTTP響應上是OK的,後端節點是可用的。預設情況的設定是:http_2xx | http_3xx

當您根據您的配置要求完成檢查模組的配置後,請首先使用nginx -t 命令監測配置檔案是否可用,然後在用nginx -s reload重啟nginx。

1.4、不得不提的tengine

Tengine是由淘寶網發起的Web伺服器專案。它在Nginx的基礎上,針對大訪問量網站的需求,添加了很多高階功能和特性。Tengine的效能和穩定性已經在大型的網站如淘寶網,天貓商城等得到了很好的檢驗。它的最終目標是打造一個高效、穩定、安全、易用的Web平臺(http://tengine.taobao.org/)。

您應該懂了,我建議您根據業務的實際情況,適時在生產環境引入Tengine。但在本部落格釋出時,Tengine的2.X版本還不穩定,所以建議實用1.5.2的穩定版本。請記住Tengine就是經過升讀改造後的Nginx。

2、後文介紹

花了兩篇文章的功夫,終於將我想給大家講解的nginx的實用特性講完了,但是nginx遠遠不止這些特性。後面有時間我們會再回到Nginx,重點講解針對Nginx的指令碼開發,我們還會講解Nginx和Lua的整合。但是為了不擾亂這個系列博文的時間安排,下篇文章我們將開始介紹LVS技術,爭取用一篇文章的篇幅講清楚LVS核心設計思想、單節點安裝和使用。再下篇文章我們介紹Keepalived技術,以及keepalived和LVS、Nginx分別進行整合,敬請關注。