原文鏈接地址:http://seanlook.com/2015/05/22/nginx-cache-check/
關(guān)于nginx的安裝和基本配置請參考nginx,本文在原基礎(chǔ)上完成以下幾個功能:
結(jié)合proxy和upstream模塊實現(xiàn)nginx負載均衡
結(jié)合nginx_upstream_check_module
模塊實現(xiàn)后端服務(wù)器的健康檢查
使用nginx-sticky-module
擴展模塊實現(xiàn)Cookie會話黏貼(session-sticky效果)
使用proxy模塊實現(xiàn)靜態(tài)文件緩存
使用ngx_cache_purge
實現(xiàn)更強大的緩存清除功能
1. 安裝及模塊說明
上面提到的3個模塊都屬于第三方擴展模塊,需要提前下好源碼,然后編譯時通過--add-moudle=src_path
一起安裝。
注意:
使用 nginx_upstream_check_module(簡記為m1) 時要先為nginx打上相應(yīng)版本的patch,我的nginx版本為 1.6.3,所以patch對應(yīng) m1 解壓后目錄下的check_1.5.12+.patch
,所以進入nginx源碼目錄,執(zhí)行 patch -p1 …(見下方示例)
nginx-sticky-module-ng(簡記為m2) 模塊可以單獨使用,但是因為m1監(jiān)控檢查的方式是依賴于m2的,所以要使用m2,還要對m1打上patch,進入m2源碼目錄,執(zhí)行 patch -p0…
編譯示例:(CentOS 6.5 x86_64, nginx 1.6.3)
# 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,而是直接拷貝可執(zhí)行文件:
# 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-ng
這個模塊的作用是通過cookie黏貼的方式將來自同一個客戶端(瀏覽器)的請求發(fā)送到同一個后端服務(wù)器上處理,這樣一定程度上可以解決多個backend servers的session同步的問題 —— 因為不再需要同步,而RR輪詢模式必須要運維人員自己考慮session同步的實現(xiàn)。
另外內(nèi)置的 ip_hash 也可以實現(xiàn)根據(jù)客戶端IP來分發(fā)請求,但它很容易造成負載不均衡的情況,而如果nginx前面有CDN網(wǎng)絡(luò)或者來自同一局域網(wǎng)的訪問,它接收的客戶端IP是一樣的,容易造成負載不均衡現(xiàn)象。淘寶Tengine的 ngx_http_upstream_session_sticky_module 也是類似的功能。nginx-sticky-module的cookie過期時間,默認瀏覽器關(guān)閉就過期,也就是會話方式。
這個模塊并不合適不支持 Cookie 或手動禁用了cookie的瀏覽器,此時默認sticky就會切換成RR。它不能與ip_hash同時使用。
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 過期時間,默認瀏覽器關(guān)閉就過期,也就是會話方式。
no_fallbackup
:如果設(shè)置了這個,cookie 對應(yīng)的服務(wù)器宕機了,那么將會返回502(bad gateway 或者 proxy error),建議不啟用
你在查看官方文檔可能會注意到里面也有個 sticky 指令,要說它們的作用幾乎是一樣的,但是你可能注意到This directive is available as part of our commercial subscription.
的說明 —— 這是nginx商業(yè)版本里才有的特性。包括后面的check
指令,在nginx的商業(yè)版本里也有對應(yīng)的health_check
(配在 location )實現(xiàn)幾乎一樣的監(jiān)控檢查功能。
2.2 load-balance其它調(diào)度方案
這里順帶介紹一下nginx的負載均衡模塊支持的其它調(diào)度算法:
輪詢
(默認) : 每個請求按時間順序逐一分配到不同的后端服務(wù)器,如果后端某臺服務(wù)器宕機,故障系統(tǒng)被自動剔除,使用戶訪問不受影響。Weight 指定輪詢權(quán)值,Weight值越大,分配到的訪問機率越高,主要用于后端每個服務(wù)器性能不均的情況下。
ip_hash
: 每個請求按訪問IP的hash結(jié)果分配,這樣來自同一個IP的訪客固定訪問一個后端服務(wù)器,有效解決了動態(tài)網(wǎng)頁存在的session共享問題。當(dāng)然如果這個節(jié)點不可用了,會發(fā)到下個節(jié)點,而此時沒有session同步的話就注銷掉了。
least_conn
: 請求被發(fā)送到當(dāng)前活躍連接最少的realserver上。會考慮weight的值。
url_hash
: 此方法按訪問url的hash結(jié)果來分配請求,使每個url定向到同一個后端服務(wù)器,可以進一步提高后端緩存服務(wù)器的效率。Nginx本身是不支持url_hash的,如果需要使用這種調(diào)度算法,必須安裝Nginx 的hash軟件包 nginx_upstream_hash 。
fair
: 這是比上面兩個更加智能的負載均衡算法。此種算法可以依據(jù)頁面大小和加載時間長短智能地進行負載均衡,也就是根據(jù)后端服務(wù)器的響應(yīng)時間來分配請求,響應(yīng)時間短的優(yōu)先分配。Nginx本身是不支持fair的,如果需要使用這種調(diào)度算法,必須下載Nginx的 upstream_fair 模塊。
3. 負載均衡與健康檢查
嚴(yán)格來說,nginx自帶是沒有針對負載均衡后端節(jié)點的健康檢查的,但是可以通過默認自帶的 ngx_http_proxy_module 模塊和 ngx_http_upstream_module 模塊中的相關(guān)指令來完成當(dāng)后端節(jié)點出現(xiàn)故障時,自動切換到下一個節(jié)點來提供訪問。
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
: 輪詢權(quán)值也是可以用在ip_hash的,默認值為1
max_fails
: 允許請求失敗的次數(shù),默認為1。當(dāng)超過最大次數(shù)時,返回proxy_next_upstream 模塊定義的錯誤。
fail_timeout
: 有兩層含義,一是在 30s 時間內(nèi)最多容許 2 次失敗;二是在經(jīng)歷了 2 次失敗以后,30s時間內(nèi)不分配請求到這臺服務(wù)器。
backup
: 預(yù)留的備份機器。當(dāng)其他所有的非backup機器出現(xiàn)故障的時候,才會請求backup機器,因此這臺機器的壓力最輕。(為什么我的1.6.3版本里配置backup啟動nginx時說invalid parameter "backup"
?)
max_conns
: 限制同時連接到某臺后端服務(wù)器的連接數(shù),默認為0即無限制。因為queue
指令是commercial,所以還是保持默認吧。
proxy_next_upstream
: 這個指令屬于 http_proxy 模塊的,指定后端返回什么樣的異常響應(yīng)時,使用另一個realserver
3.2 nginx_upstream_check_module
nginx_upstream_check_module 是專門提供負載均衡器內(nèi)節(jié)點的健康檢查的外部模塊,由淘寶的姚偉斌大神開發(fā),通過它可以用來檢測后端 realserver 的健康狀態(tài)。如果后端 realserver 不可用,則后面的請求就不會轉(zhuǎn)發(fā)到該節(jié)點上,并持續(xù)檢查幾點的狀態(tài)。在淘寶自己的 tengine 上是自帶了該模塊。項目地址:https://github.com/yaoweibin/nginx_upstream_check_module 。
下面的是一個帶后端監(jiān)控檢查的 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這個負載均衡條目中的所有節(jié)點,每個5秒檢測一次,請求2次正常則標(biāo)記 realserver狀態(tài)為up,如果檢測 3 次都失敗,則標(biāo)記 realserver的狀態(tài)為down,超時時間為1秒。
check指令只能出現(xiàn)在upstream中:
interval
: 向后端發(fā)送的健康檢查包的間隔。
fall
: 如果連續(xù)失敗次數(shù)達到fall_count,服務(wù)器就被認為是down。
rise
: 如果連續(xù)成功次數(shù)達到rise_count,服務(wù)器就被認為是up。
timeout
: 后端健康請求的超時時間。
default_down
: 設(shè)定初始時服務(wù)器的狀態(tài),如果是true,就說明默認是down的,如果是false,就是up的。默認值是true,也就是一開始服務(wù)器認為是不可用,要等健康檢查包達到一定成功次數(shù)以后才會被認為是健康的。
type
:健康檢查包的類型,現(xiàn)在支持以下多種類型tcp
:簡單的tcp連接,如果連接成功,就說明后端正常。
http
:發(fā)送HTTP請求,通過后端的回復(fù)包的狀態(tài)來判斷后端是否存活。
ajp
:向后端發(fā)送AJP協(xié)議的Cping包,通過接收Cpong包來判斷后端是否存活。
ssl_hello
:發(fā)送一個初始的SSL hello包并接受服務(wù)器的SSL hello包。
mysql
: 向mysql服務(wù)器連接,通過接收服務(wù)器的greeting包來判斷后端是否存活。
fastcgi
:發(fā)送一個fastcgi請求,通過接受解析fastcgi響應(yīng)來判斷后端是否存活
port
: 指定后端服務(wù)器的檢查端口。你可以指定不同于真實服務(wù)的后端服務(wù)器的端口,比如后端提供的是443端口的應(yīng)用,你可以去檢查80端口的狀態(tài)來判斷后端健康狀況。默認是0,表示跟后端server提供真實服務(wù)的端口一樣。該選項出現(xiàn)于Tengine-1.4.0。
如果 type 為 http ,你還可以使用check_http_send
來配置http監(jiān)控檢查包發(fā)送的請求內(nèi)容,為了減少傳輸數(shù)據(jù)量,推薦采用 HEAD 方法。當(dāng)采用長連接進行健康檢查時,需在該指令中添加keep-alive請求頭,如: HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n
。當(dāng)采用 GET 方法的情況下,請求uri的size不宜過大,確保可以在1個interval內(nèi)傳輸完成,否則會被健康檢查模塊視為后端服務(wù)器或網(wǎng)絡(luò)異常。
check_http_expect_alive
指定HTTP回復(fù)的成功狀態(tài),默認認為 2XX 和 3XX 的狀態(tài)是健康的。
4. nginx的proxy緩存使用
nginx的頁面緩存功能與上面的負載均衡和健康檢查是沒有關(guān)系的,放在這里一是因為懶得再起一篇文章,二是再有l(wèi)oad-balance的地方一般都會啟用緩存的。
緩存也就是將js、css、image等靜態(tài)文件從tomcat緩存到nginx指定的緩存目錄下,既可以減輕tomcat負擔(dān),也可以加快訪問速度,但這樣緩存及時清理成為了一個問題,所以需要 ngx_cache_purge
這個模塊來在過期時間未到之前,手動清理緩存。(這里有篇 文章,對比使用緩存、不使用緩存、使用動靜分離三種情況下,高并發(fā)性能比較。使用代理緩存功能性能會高出很多倍)
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(/.*) {
#設(shè)置只允許指定的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
: 緩存臨時目錄。后端的響應(yīng)并不直接返回客戶端,而是先寫到一個臨時文件中,然后被rename一下當(dāng)做緩存放在 proxy_cache_path 。0.8.9版本以后允許temp和cache兩個目錄在不同文件系統(tǒng)上(分區(qū)),然而為了減少性能損失還是建議把它們設(shè)成一個文件系統(tǒng)上。
proxy_cache_path ...
: 設(shè)置緩存目錄,目錄里的文件名是 cache_key 的MD5值。levels=1:2 keys_zone=cache_one:50m
表示采用2級目錄結(jié)構(gòu),Web緩存區(qū)名稱為cache_one,內(nèi)存緩存空間大小為100MB,這個緩沖zone可以被多次使用。文件系統(tǒng)上看到的緩存文件名類似于 /usr/local/nginx-1.6/proxy_cache/c/29/b7f54b2df7773722d382f4809d65029c 。inactive=2d max_size=2g
表示2天沒有被訪問的內(nèi)容自動清除,硬盤最大緩存空間為2GB,超過這個大學(xué)將清除最近最少使用的數(shù)據(jù)。
proxy_cache
: 引用前面定義的緩存區(qū) cache_one
proxy_cache_key
: 定義cache_key
proxy_cache_valid
: 為不同的響應(yīng)狀態(tài)碼設(shè)置不同的緩存時間,比如200、302等正常結(jié)果可以緩存的時間長點,而404、500等緩存時間設(shè)置短一些,這個時間到了文件就會過期,而不論是否剛被訪問過。
expires
: 在響應(yīng)頭里設(shè)置Expires:
或Cache-Control:max-age
,返回給客戶端的瀏覽器緩存失效時間。
關(guān)于緩存的失效期限上面有三個選項:X-Accel-Expires
、inactive
、proxy_cache_valid
、expires
,它們之間是有優(yōu)先級的,按上面的順序如果在header里設(shè)置 X-Accel-Expires 則它的優(yōu)先級最高,否則inactive優(yōu)先級最高。更多資料請參考 nginx緩存優(yōu)先級 或這里。
清除緩存
上述配置的proxy_cache_purge
指令用于方便的清除緩存,但必須按照第三方的 ngx_cache_purge 模塊才能使用,項目地址:https://github.com/FRiCKLE/ngx_cache_purge/ 。
使用 ngx_cache_purge 模塊清除緩存有2種辦法(直接刪除緩存目錄下的文件也算一種辦法):
echo發(fā)送PURGE指令proxy_cache_purge PURGE from 127.0.0.1
表示只允許在來自本地的清除指令
# echo -e 'PURGE / HTTP/1.0\r\n' | nc 127.0.0.1 80
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
參考
official documentation
Nginx實戰(zhàn)系列之功能篇—-后端節(jié)點健康檢查
Tengine nginx_upstream_check_module
nginx反向代理tomcat集群做負載均衡緩存
web內(nèi)容緩存 nginx高性能緩存詳解
使用nginx sticky實現(xiàn)基于cookie的負載均衡