[轉]Nginx負載均衡原理初解

什麼是負載均衡php

 

咱們知道單臺服務器的性能是有上限的,當流量很大時,就須要使用多臺服務器來共同提供服務,這就是所謂的集羣。html

負載均衡服務器,就是用來把通過它的流量,按照某種方法,分配到集羣中的各臺服務器上。這樣一來不只能夠承擔java

更大的流量、下降服務的延遲,還能夠避免單點故障形成服務不可用。通常的反向代理服務器,都具有負載均衡的功能。linux

負載均衡功能能夠由硬件來提供,好比之前的F5設備。也能夠由軟件來提供,LVS能夠提供四層的負載均衡(利用IP和端口),nginx

Haproxy和Nginx能夠提供七層的負載均衡(利用應用層信息)。程序員

 

來看一個最簡單的Nginx負載均衡配置。web

[html]  view plain  copy
 
  1. http {  
  2.     upstream cluster {  
  3.         server srv1;  
  4.         server srv2;  
  5.         server srv3;  
  6.     }  
  7.    
  8.     server {  
  9.         listen 80;  
  10.   
  11.         location / {  
  12.             proxy_pass http://cluster;  
  13.         }  
  14.     }  
  15. }  

經過上述配置,Nginx會做爲HTTP反向代理,把訪問本機的HTTP請求,均分到後端集羣的3臺服務器上。正則表達式

此時使用的HTTP反向代理模塊是ngx_http_proxy_module。算法

通常在upstream配置塊中要指明使用的負載均衡算法,好比hash、ip_hash、least_conn。ubuntu

這裏沒有指定,因此使用了默認的HTTP負載均衡算法 - 加權輪詢。

 

負載均衡流程圖

 

在描述負載均衡模塊的具體實現前,先來看下它的大體流程:

 

 

負載均衡模塊 

 

Nginx目前提供的負載均衡模塊:

ngx_http_upstream_round_robin,加權輪詢,可均分請求,是默認的HTTP負載均衡算法,集成在框架中。

ngx_http_upstream_ip_hash_module,IP哈希,可保持會話。

ngx_http_upstream_least_conn_module,最少鏈接數,可均分鏈接。

ngx_http_upstream_hash_module,一致性哈希,可減小緩存數據的失效。

 

以上負載均衡模塊的實現,基本上都遵循一套類似的流程。

 

1. 指令的解析函數

好比least_conn、ip_hash、hash指令的解析函數。

這些函數在解析配置文件時調用,主要用於:

檢查指令參數的合法性

指定peer.init_upstream函數指針的值,此函數用於初始化upstream塊。

 

2. 初始化upstream塊

在執行完指令的解析函數後,緊接着會調用全部HTTP模塊的init main conf函數。

在執行ngx_http_upstream_module的init main conf函數時,會調用全部upstream塊的初始化函數,

即在第一步中指定的peer.init_upstream,主要用於:

建立和初始化後端集羣,保存該upstream塊的數據

指定peer.init,此函數用於初始化請求的負載均衡數據

 

來看下ngx_http_upstream_module。

[java]  view plain  copy
 
  1. ngx_http_module_t ngx_http_upstream_module_ctx = {  
  2.     ...  
  3.     ngx_http_upstream_init_main_conf, /* init main configuration */  
  4.     ...  
  5. };  
[java]  view plain  copy
 
  1. static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)  
  2. {  
  3.     ...  
  4.     /* 數組的元素類型是ngx_http_upstream_srv_conf_t */  
  5.     for (i = 0; i < umcf->upstreams.nelts; i++) {  
  6.         /* 若是沒有指定upstream塊的初始化函數,默認使用round robin的 */  
  7.         init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream :  
  8.                         ngx_http_upstream_init_round_robin;  
  9.   
  10.         if (init(cf, uscfp[i] != NGX_OK) {  
  11.             return NGX_CONF_ERROR;  
  12.         }  
  13.     }  
  14.     ...  
  15. }  

 

3. 初始化請求的負載均衡數據塊

當收到一個請求後,通常使用的反向代理模塊(upstream模塊)爲ngx_http_proxy_module,

其NGX_HTTP_CONTENT_PHASE階段的處理函數爲ngx_http_proxy_handler,在初始化upstream機制的

函數ngx_http_upstream_init_request中,調用在第二步中指定的peer.init,主要用於:

建立和初始化該請求的負載均衡數據塊

指定r->upstream->peer.get,用於從集羣中選取一臺後端服務器(這是咱們最爲關心的)

指定r->upstream->peer.free,當不用該後端時,進行數據的更新(無論成功或失敗都調用)

 

請求的負載均衡數據塊中,通常會有一個成員指向對應upstream塊的數據,除此以外還會有本身獨有的成員。

"The peer initialization function is called once per request. 
It sets up a data structure that the module will use as it tries to find an appropriate
backend server to service that request; this structure is persistent across backend re-tries,
so it's a convenient place to keep track of the number of connection failures, or a computed
hash value. By convention, this struct is called ngx_http_upstream_<module_name>_peer_data_t."

 

4. 選取一臺後端服務器

通常upstream塊中會有多臺後端,那麼對於本次請求,要選定哪一臺後端呢?

這時候第三步中r->upstream->peer.get指向的函數就派上用場了:

採用特定的算法,好比加權輪詢或一致性哈希,從集羣中選出一臺後端,處理本次請求。 

選定後端的地址保存在pc->sockaddr,pc爲主動鏈接。

函數的返回值:

NGX_DONE:選定一個後端,和該後端的鏈接已經創建。以後會直接發送請求。

NGX_OK:選定一個後端,和該後端的鏈接還沒有創建。以後會和後端創建鏈接。

NGX_BUSY:全部的後端(包括備份集羣)都不可用。以後會給客戶端發送502(Bad Gateway)。

 

5. 釋放一臺後端服務器

當再也不使用一臺後端時,須要進行收尾處理,好比統計失敗的次數。

這時候會調用第三步中r->upstream->peer.free指向的函數。

函數參數state的取值:

0,請求被成功處理

NGX_PEER_FAILED,鏈接失敗

NGX_PEER_NEXT,鏈接失敗,或者鏈接成功但後端未能成功處理請求

 

一個請求容許嘗試的後端數爲pc->tries,在第三步中指定。當state爲後兩個值時:

若是pc->tries不爲0,須要從新選取一個後端,繼續嘗試,此後會重複調用r->upstream->peer.get。

若是pc->tries爲0,便再也不嘗試,給客戶端返回502錯誤碼(Bad Gateway)。

 

在upstream模塊的回調

 

負載均衡模塊的功能是從後端集羣中選取一臺後端服務器,而具體的反向代理功能是由upstream模塊實現的,

好比和後端服務器創建鏈接、向後端服務器發送請求、處理後端服務器的響應等。

咱們來看下負載均衡模塊提供的幾個鉤子函數,是在upstream模塊的什麼地方回調的。

 

Nginx的HTTP反向代理模塊爲ngx_http_proxy_module,其NGX_HTTP_CONTENT_PHASE階段的處理函數爲

ngx_http_proxy_handler,每一個請求的upstream機制是從這裏開始的。

[java]  view plain  copy
 
  1. ngx_http_proxy_handler  
  2.     ngx_http_upstream_create /* 建立請求的upstream實例 */  
  3.     ngx_http_upstream_init /* 啓動upstream機制 */  
  4.         ngx_htp_upstream_init_request /* 負載均衡模塊的入口 */  
  5.   
  6.             uscf->peer.init(r, uscf) /* 第三步,初始化請求的負載均衡數據塊 */  
  7.             ...  
  8.   
  9.             ngx_http_upstream_connect /* 可能會被ngx_http_upstream_next重複調用 */  
  10.   
  11.                 ngx_event_connect_peer(&u->peer); /* 鏈接後端 */  
  12.                     pc->get(pc, pc->data); /* 第四步,從集羣中選取一臺後端 */          
  13.                 ...  
  14.   
  15.                 /* 和後端建連成功後 */  
  16.                 c = u->peer.connection;  
  17.                 c->data = r;  
  18.                 c->write->handler = ngx_http_upstream_handler; /* 註冊的鏈接的讀事件處理函數 */  
  19.                 c->read->handler = ngx_http_upstream_handler; /* 註冊的鏈接的寫事件處理函數 */                  
  20.                 u->write_event_handler = ngx_http_upstream_send_request_handler; /* 寫事件的真正處理函數 */  
  21.                 u->read_event_handler = ngx_http_upstream_process_header; /* 讀事件的真正處理函數 */  

選定後端以後,在和後端通訊的過程當中若是發生了錯誤,會調用ngx_http_upstream_next來繼續嘗試其它的後端。

[java]  view plain  copy
 
  1. ngx_http_upstream_next  
  2.     if (u->peer.sockaddr) {  
  3.           if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403 ||  
  4.                ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404)  
  5.                state = NGX_PEER_NEXT;  
  6.           else  
  7.                state = NGX_PEER_FAILED;  
  8.   
  9.           /* 第五步,釋放後端服務器 */  
  10.           u->peer.free(&u->peer, u->peer.data, state);  
  11.           u->peer.sockaddr = NULL;  
  12.      }  

 

Reference

 

[1]. http://www.evanmiller.org/nginx-modules-guide.html#proxying

[2]. http://tengine.taobao.org/book/chapter_05.html#id5

 

---------------------

下載nginx源碼包,編譯nginx須要指定pcre,zlib,openssl,到官網上下載源代碼包:
http://www.zlib.NET/
http://www.openssl.org/
http://www.pcre.org/

將這三個包下載放到/opt目錄,tar -xzvf *.gz解壓,而後也將nginx-0.6.32的包解壓到/opt目錄下,進入nginx目錄,執行:
#./configure --sbin-path=/usr/local/sbin --with-http_ssl_module --with-pcre=../pcre-7.7 --with-zlib=../zlib-1.2.3 --with-openssl=../openssl-0.9.8g
#make && make install

若是在./configure時出如今錯誤,多是沒有安裝gcc g+編譯器的緣故。單獨安裝這兩個編譯器比較麻煩,ubuntu提供了build-essential來安裝gcc和g++編譯器

apt-get install build-essential

 

採用aptitude安裝的時候,系統會將全部依賴的包都一併裝上,可是使 用源碼編譯的時候就沒這麼智能了,咱們須要找到須要的依賴包,而後手工安裝,幸運的是,這並不複雜,也很少,例如pcre, ssl 和zlib,安裝方法比較簡單:

sudo aptitude install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev

3、安裝Nginx

ok,準備工做作完了,是時候開始下載、 安裝Nginx了。

一、下載源代碼

       到Nignx官網去下載源代碼

二、 解壓

tar -zxvf nginx-0.6.31.tar.gz
...
cd nginx-0.6.31/

三、選擇須要的編譯選項
Nginx的編譯選項仍是很多 的,基本上都是定製位置和模塊,分別是:
1)--sbin-path=/usr/local/sbin
從源碼編譯Nginx會安裝在/usr/local/nginx目錄下(你可使用參數--prefix=<path>指定本身須要的位置),而後會將bin文件放在/usr/local/nginx/sbin/nginx,雖然比較清晰,可是和咱們通常的習慣不一樣

(做爲程序員的咱們更習慣在/usr/local /sbin下尋找bin文件);

2)--with-http_ssl_module
主要是提供https訪問支持的。

五、 Compile

./configure --sbin-path=/usr/local/sbin --with-http_ssl_module

編 譯的時間不會很長,完成的時候你會在屏幕上看到相似下面的信息:

...
nginx path prefix: "/usr/local/nginx"
nginx binary file: "/usr/local/sbin"
nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
...

留 意上面的提示,涉及到nginx的幾個重要文件的路徑信息。

六、Make && make install
差很少快完成了,如今make一下。

make

sudo make install

在使用make install 命令時可能會提示當前執行的命令權限不夠,sudo su命令而後輸入密碼提高下權限就ok

七、chmod(可選)
還須要給bin文件有執行權限,也比較簡單:

chmod +x /usr/local/sbin/nginx

 

八、Nginx重要文件安裝目錄

默認nginx安裝的目錄在/usr/local/nginx下,包括:
/usr/local/nginx/sbin #nginx啓動文件
/usr/local/nginx/conf #配置文件
/usr/local/nginx/html #默認網頁文件
/usr/local/nginx/logs #日誌文件

4、使用

安裝完成後,試着使用下。
一、啓動

sudo /usr/local/sbin/nginx

而後把本身的瀏覽器導航到http://IP就可 以看到默認的歡迎界面了

 

Welcome to nginx!

 

If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.

For online documentation and support please refer tonginx.org.
Commercial support is available atnginx.com.

Thank you for using nginx.

 

二、中止

 

   sudo /usr/local/sbin/nginx -s stop


 

 

6、附錄:Compile-time options

(原文參考:http://wiki.codemongers.com/NginxInstallOptions )

configure 腳本肯定系統所具備一些特性,特別是 nginx 用來處理鏈接的方法。而後,它建立 Makefile 文件。

configure 支持下面的選項:

1)目錄屬性

--prefix=<path> - Nginx安裝路徑。若是沒有指定,默認爲 /usr/local/nginx。

--sbin-path=<path> - Nginx可執行文件安裝路徑。只能安裝時指定,若是沒有指定,默認爲<prefix>/sbin/nginx。

--conf-path=<path> - 在沒有給定-c選項下默認的nginx.conf的路徑。若是沒有指定,默認爲<prefix>/conf/nginx.conf。

--pid-path=<path> - 在nginx.conf中沒有指定pid指令的狀況下,默認的nginx.pid的路徑。若是沒有指定,默認爲 <prefix>/logs/nginx.pid。

--lock-path=<path> - nginx.lock文件的路徑,默認爲<prefix>/logs/nginx.lock

--error-log-path=<path> - 在nginx.conf中沒有指定error_log指令的狀況下,默認的錯誤日誌的路徑。若是沒有指定,默認爲 <prefix>/logs/error.log。

--http-log-path=<path> - 在nginx.conf中沒有指定access_log指令的狀況下,默認的訪問日誌的路徑。若是沒有指定,默認爲 <prefix>/logs/access.log。

--user=<user> - 在nginx.conf中沒有指定user指令的狀況下,默認的nginx使用的用戶。若是沒有指定,默認爲 nobody。

--group=<group> - 在nginx.conf中沒有指定user指令的狀況下,默認的nginx使用的組。若是沒有指定,默認爲 nobody。

--builddir=DIR - 指定編譯的目錄

 

2)模塊

--with-rtsig_module - 啓用 rtsig 模塊

--with-select_module --without-select_module -容許或不容許開啓SELECT模式,若是 configure 沒有找到更合適的模式,好比:kqueue(sun os),epoll (Linux kenel 2.6+), rtsig(實時信號)或者/dev/poll(一種相似select的模式,底層實現與SELECT基本相 同,都是採用輪訓方法) SELECT模式將是默認安裝模式

--with-poll_module --without-poll_module - Whether or not to enable the poll module. This module is enabled by default if a more suitable method such as kqueue, epoll, rtsig or /dev/poll is not discovered by configure.

--with-http_ssl_module -開啓HTTP SSL模塊,使NGINX能夠支持HTTPS請求。這個模塊須要已經安裝了OPENSSL,在DEBIAN上是libssl

--with-http_realip_module - 啓用 ngx_http_realip_module

--with-http_addition_module - 啓用 ngx_http_addition_module

--with-http_sub_module - 啓用 ngx_http_sub_module

--with-http_dav_module - 啓用 ngx_http_dav_module

--with-http_flv_module - 啓用 ngx_http_flv_module

--with-http_stub_status_module - 啓用 "server status" 頁

--without-http_charset_module - 禁用 ngx_http_charset_module

--without-http_gzip_module - 禁用 ngx_http_gzip_module. 若是啓用,須要 zlib 。

--without-http_ssi_module - 禁用 ngx_http_ssi_module

--without-http_userid_module - 禁用 ngx_http_userid_module

--without-http_access_module - 禁用 ngx_http_access_module

--without-http_auth_basic_module - 禁用 ngx_http_auth_basic_module

--without-http_autoindex_module - 禁用 ngx_http_autoindex_module

--without-http_geo_module - 禁用 ngx_http_geo_module

--without-http_map_module - 禁用 ngx_http_map_module

--without-http_referer_module - 禁用 ngx_http_referer_module

--without-http_rewrite_module - 禁用 ngx_http_rewrite_module. 若是啓用須要 PCRE 。

--without-http_proxy_module - 禁用 ngx_http_proxy_module

--without-http_fastcgi_module - 禁用 ngx_http_fastcgi_module

--without-http_memcached_module - 禁用 ngx_http_memcached_module

--without-http_limit_zone_module - 禁用 ngx_http_limit_zone_module

--without-http_empty_gif_module - 禁用 ngx_http_empty_gif_module

--without-http_browser_module - 禁用 ngx_http_browser_module

--without-http_upstream_ip_hash_module - 禁用 ngx_http_upstream_ip_hash_module

--with-http_perl_module - 啓用 ngx_http_perl_module

--with-perl_modules_path=PATH - 指定 perl 模塊的路徑

--with-perl=PATH - 指定 perl 執行文件的路徑

--http-log-path=PATH - Set path to the http access log

--http-client-body-temp-path=PATH - Set path to the http client request body temporary files

--http-proxy-temp-path=PATH - Set path to the http proxy temporary files

--http-fastcgi-temp-path=PATH - Set path to the http fastcgi temporary files

--without-http - 禁用 HTTP server

--with-mail - 啓用 IMAP4/POP3/SMTP 代理模塊

--with-mail_ssl_module - 啓用 ngx_mail_ssl_module

--with-cc=PATH - 指定 C 編譯器的路徑

--with-cpp=PATH - 指定 C 預處理器的路徑

--with-cc-opt=OPTIONS - Additional parameters which will be added to the variable CFLAGS. With the use of the system library PCRE in FreeBSD, it is necessary to indicate --with-cc-opt="-I /usr/local/include". If we are using select() and it is necessary to increase the number of file descriptors, then this also can be assigned here: --with-cc-opt="-D FD_SETSIZE=2048".

--with-ld-opt=OPTIONS - Additional parameters passed to the linker. With the use of the system library PCRE in FreeBSD, it is necessary to indicate --with-ld-opt="-L /usr/local/lib".

--with-cpu-opt=CPU - 爲特定的 CPU 編譯,有效的值包括:pentium, pentiumpro, pentium3, pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64

--without-pcre - 禁止 PCRE 庫的使用。同時也會禁止 HTTP rewrite 模塊。在 "location" 配置指令中的正則表達式也須要 PCRE 。

--with-pcre=DIR - 指定 PCRE 庫的源代碼的路徑。

--with-pcre-opt=OPTIONS - Set additional options for PCRE building.

--with-md5=DIR - Set path to md5 library sources.

--with-md5-opt=OPTIONS - Set additional options for md5 building.

--with-md5-asm - Use md5 assembler sources.

--with-sha1=DIR - Set path to sha1 library sources.

--with-sha1-opt=OPTIONS - Set additional options for sha1 building.

--with-sha1-asm - Use sha1 assembler sources.

--with-zlib=DIR - Set path to zlib library sources.

--with-zlib-opt=OPTIONS - Set additional options for zlib building.

--with-zlib-asm=CPU - Use zlib assembler sources optimized for specified CPU, valid values are: pentium, pentiumpro

--with-openssl=DIR - Set path to OpenSSL library sources

--with-openssl-opt=OPTIONS - Set additional options for OpenSSL building

--with-debug - 啓用調試日誌

--add-module=PATH - Add in a third-party module found in directory PAT

---------------------

【轉】nginx proxy_cache 緩存配置

 
 
 

前言:

因爲本人工做緣由,涉及到網絡直播領域,其中視頻的回放下載,涉及到了一些視頻下載方面的技術。針對於一個完整視頻的下載,目前市面上的主流作法是,先將整個視頻流切片,存儲到文件服務器中,在用戶須要觀看回放視頻時。經過一個視頻回源服務器,去文件服務器中逐個請求切片,返回給用戶播放。
今天着重探討的是關於回源服務器緩存的配置以及合理的緩存策略。

經過給回源服務器配置緩存的案例,詳細講解一整套緩存配置機制,而且可沿用到其餘任何緩存配置場景中。

 

今天的講解分爲四點:
  • 回源服務器的工做是啥
  • 爲啥須要給回源服務器加緩存
  • 如何配置緩存
  • 如何針對業務場景配置完備的緩存機制
 

回源服務器的工做:

回源服務器在下面敘述中簡稱:源站
如圖所示,在文件下載的過程當中,橫跨在cdn與文件服務器之間,做爲下載樞紐。

 

源站架構:源站是nginx+PHP的webserver架構,如圖所示:

 

但若是源站只是簡單的收到請求,而後下載資源,再返回,勢必會存在如下幾點不夠優化的問題:
一、cdn可能存在屢次回源現象
二、源站對同一資源的屢次下載,存在網絡流量帶寬浪費,以及沒必要要的耗時。
因此爲了優化這些問題,須要給源站作一層緩存。緩存策略採用nginx自帶的proxy_cache模塊。
 

proxy_cache原理:

proxy_cache模塊的工做原理如圖所示:
 

如何配置proxy_cache模塊

在nginx.conf文件中添加以下代碼:
[plain]  view plain  copy
 
  1. http{  
  2.     ......  
  3.     proxy_cache_path/data/nginx/tmp-test levels=1:2 keys_zone=tmp-test:100m inactive=7d max_size=1000g;  
  4. }  
代碼說明:

proxy_cache_path 緩存文件路徑

levels 設置緩存文件目錄層次;levels=1:2 表示兩級目錄

keys_zone 設置緩存名字和共享內存大小

inactive 在指定時間內沒人訪問則被刪除

max_size 最大緩存空間,若是緩存空間滿,默認覆蓋掉緩存時間最長的資源。
 

當配置好以後,重啓nginx,若是不報錯,則配置的proxy_cache會生效

 

查看  proxy_cache_path /data/nginx/目錄,
會發現生成了tmp-test文件夾。
 

如何使用proxy_cache

在你對應的nginx vhost server配置文件中添加以下代碼:
[plain]  view plain  copy
 
  1. location /tmp-test/ {  
  2.   proxy_cache tmp-test;  
  3.   proxy_cache_valid  200 206 304 301 302 10d;  
  4.   proxy_cache_key $uri;  
  5.   proxy_set_header Host $host:$server_port;  
  6.   proxy_set_header X-Real-IP $remote_addr;  
  7.   proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;  
  8.   proxy_passhttp://127.0.0.1:8081/media_store.php/tmp-test/;  
  9. }  
配置項介紹:
Proxy_cache tmp-test 使用名爲tmp-test的對應緩存配置

proxy_cache_valid  200 206 304 301 302 10d; 對httpcode爲200…的緩存10天

proxy_cache_key $uri  定義緩存惟一key,經過惟一key來進行hash存取

proxy_set_header  自定義http header頭,用於發送給後端真實服務器。

proxy_pass  指代理後轉發的路徑,注意是否須要最後的/
 
到這裏,最基本的proxy_cache功能就配置成功了。當uri成功匹配到該location,則proxy_cache就會生效。
 

添加proxy_cache以後,請求過程的變化:

一、第一次訪問:
 
第一次訪問,proxy_cache並無找到對應的緩存文件(未命中緩存MISS),因此當第一次請求完成的同時,proxy_cache會保持緩存:
二、保存緩存,如圖所示:
三、同一個url第二次訪問,當同一個文件再次到達源站,proxy_cache就會找到其對應的緩存文件(命中緩存HIT)直接返回給請求端,無需再執行php程序,如圖所示:
 

提出疑問:

到此,就完成了最基本的proxy_cache配置和訪問過程介紹,可是最基本的配置,每每沒法知足咱們的業務需求,咱們每每會提出如下幾點疑問和需求:
  1. 須要主動清理緩存文件
  2. 寫入路徑爲一塊磁盤,若是磁盤打滿該怎麼解決?
  3. 如何讓源站支持斷點續傳,以及斷點續傳的緩存策略
  4. 若是請求端 range 請求(分片下載)一個大資源,一樣的uri,如何區別請求?
  5. 還須要告訴請求端,資源的過時時間
  6. 日誌統計,如何配置命中與不命中字段,如何作統計?
面對以上疑問,咱們一個一個解決。
 

問題一:主動清理緩存

採用:nginx  proxy_cache_purge 模塊 ,該模塊與proxy_cache成對出現,功能正好相反。
設計方法:在nginx中,另啓一個server,當須要清理響應資源的緩存時,在本機訪問這個server。
例如:
訪問 127.0.0.1:8083/tmp-test/TL39ef7ea6d8e8d48e87a30c43b8f75e30.txt 便可清理該資源的緩存文件。
配置方法:
[plain]  view plain  copy
 
  1. location /tmp-test/ {  
  2.                 allow 127.0.0.1; //只容許本機訪問  
  3.                 deny all; //禁止其餘全部ip  
  4.                 proxy_cache_purge tmp-test $uri;  //清理緩存  
  5.         }  
proxy_cache_purge:緩存清理模塊
tmp-test:指定的key_zone
$uri:指定的生成key的參數
proxy_cache_purge緩存清理過程,如圖所示:


問題二:緩存文件強磁盤打滿該怎麼辦?

因爲寫入路徑爲一個單一目錄,只能寫入一塊磁盤。一塊磁盤很快就會被打滿,解決該問題有以下兩種方法:
一、將多塊磁盤作磁盤陣列? 缺點是:減少了實際的存儲空間。
二、巧妙得運用proxy_cache_path的目錄結構,因爲levels=1:2,這致使緩存文件的目錄結構爲兩層,每層目錄名,都是由hash函數生成。如圖所示:
總共含有16*16*16=4096個文件目錄。對該一級目錄進行軟鏈接,分別將0-f軟鏈接到你所須要的指定磁盤目錄上,如圖所示:
經過軟鏈的方法,實現:將不一樣盤下的目錄做爲真正存放數據的路徑,解決了多盤利用,單盤被打滿的問題。
 

問題三:支持range(斷點續傳)

添加上緩存代理以後,客戶端發起的range請求將會失效,以下圖所示:
致使range參數沒法傳遞到下一級的緣由以下:
當緩存代理轉發http請求到後端服務器時,http header會改變,header中的部分參數,會被取消掉。其中range參數被取消,致使,後端nginx服務器沒有收到range參數,最終致使這個分片下載不成功。因此須要對代理轉發的header進行配置。
例如:
[plain]  view plain  copy
 
  1. location /tmp-test/ {  
  2.                 proxy_cache tmp-test;  
  3.                 proxy_cache_valid  200 206 304 301 302 10d;  
  4.                 proxy_cache_key $uri;  
  5.                 <span style="color:#ff0000;">proxy_set_header Range $http_range;</span>  
  6.                 proxy_pass http://127.0.0.1:8081/media_store.php/tmp-test/;  
  7. }  
紅色部分的含義:將http請求中的range值($http_range)放到代理轉發的http請求頭中做爲參數range的值。
 

問題四,當支持range加載後,proxy_cache_key,則須要從新配置:

若是請求端 Range請求(分片下載)一個大資源,一樣的uri,proxy cache如何識別資源對應的key。
因爲nginx配置爲:proxy_cache_key $uri,用uri做爲key
因此當請求爲普通請求和range請求時,都是一樣的uri做爲key。proxy_cache將有可能致使錯誤返回。以下圖所示:

解決方法以下:
修改proxy_cache_key ,配置proxy_cache_key $http_range$uri;
這樣就能解決:key惟一性。能夠避免無論是正常請求仍是不一樣的range請求,第一次獲取的內容和以後獲取的緩存內容都不會出現異常。

問題五:如何配置-返回過時時間

須要經過返回過時時間來指定請求端,哪些資源須要緩存,哪些資源不緩存,
 
 
參數 正常請求 range請求
返回過時時間 返回 不返回
爲了防止請求端將分片資源當作完整資源緩存起來,咱們須要對正常請求,返回過時時間;對range請求, 不返回過時時間。
解決該問題,經過對nginx配置便可解決:
[plain]  view plain  copy
 
  1. location /media_store.php {  
  2.      fastcgi_pass   127.0.0.1:9000;  
  3.      fastcgi_index  media_store.php;  
  4.      fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;  
  5.      include        fastcgi_params;  
  6.      if ( $http_range = ''){  
  7.           expires 2592000s;  
  8.      }  
  9. }  
在proxy_pass代理以後的location中加入對$http_range的判斷,expires 表示過時時間。 2592000s指緩存過時時間。
 

問題七:緩存命中狀況如何在http頭中體現,以及在nginx日誌中查看

解決方法:
利用nginx $upstream_cache_status變量:該變量表明緩存命中的狀態,
若是命中,爲HIT;若是未命中,爲MISS
在返回nginx server配置中添加:
add_header  Nginx-Cache "$upstream_cache_status";
在nginxlog中添加:
log_format       combinedio  …$upstream_cache_status;
http返回head截圖:

nginx log日誌截圖:
 

總結:

整個一套完備的緩存策略就介紹到此,這套方案中不只實現了基本的緩存配置,還解決了實際場景應用中會遇到的,磁盤擴展,緩存清理,斷點續傳,緩存過時時間,緩存命中提示等問題,只要將這套方案靈活運用,無論是再複雜的場景,基本都能知足需求。以上都是我在工做中爬過的坑,不斷完善總結出的結果,但願對讀者能有幫助。
相關文章
相關標籤/搜索