1、簡介
Nginx版本從0.7.48開始,支持了相似Squid的緩存功能。這個緩存是把URL及相關組合當作Key,用Md5算法對Key進行哈希,獲得硬盤上對應的哈希目錄路徑,從而將緩存內容保存在該目錄內。php
Nginx Web 緩存服務只能爲指定URL或狀態碼設置過時時間,不支持相似Squid的PURGE指令手動清除緩存;可是咱們能夠經過Nginx的模塊ngx_cache_purge清除指定URL的緩存。html
- proxy_cache:緩存後端服務器的內容,多是任何內容,包括靜態的和動態,減小了nginx與後端通訊的次數,節省了傳輸時間和後端寬帶
- fastcgi_cache:緩存fastcgi生成的內容,不少狀況是php生成的動態的內容,少了nginx與php的通訊的次數,更減輕了php和數據庫(mysql)的壓力,這比用memcached之類的緩存要輕鬆得多
圖片來自網絡mysql
2、配置
nginx.confnginx
1
2
3
4
5
|
fastcgi_cache_path /
var
/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key
"$scheme$request_method$host$request_uri"
;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_temp_path /tmp/nginx/fcgi/temp;
|
vhost配置算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
server {
server_name example.com www.example.com;
access_log /
var
/log/nginx/example.com.access.log;
error_log /
var
/log/nginx/example.com.error.log;
root /
var
/www/example.com/htdocs;
index index.php;
set
$skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if
($request_method = POST) {
set
$skip_cache 1;
}
if
($query_string !=
""
) {
set
$skip_cache 1;
}
# Don't cache uris containing the following segments
if
($request_uri ~*
"/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml"
) {
set
$skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if
($http_cookie ~*
"comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in"
) {
set
$skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php($|/) {
try_files $uri =404;
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/dev/shm/php-socket;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache WORDPRESS;
include fcgi_cache_params;
}
location ~ /purge(/.*) {
fastcgi_cache_purge WORDPRESS
"$scheme$request_method$host$1"
;
}
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\. { deny all; access_log off; log_not_found off; }
}
|
fcgi_cache_params配置sql
1
2
3
4
5
6
7
8
9
10
11
12
|
#include fcgi_cache_params;
#fastcgi_cache_valid 200 302 1s;
### fcgi-cache
fastcgi_cache fcgi;
fastcgi_cache_valid 200 302 1s;
fastcgi_cache_valid 404 500 502 503 504 0s;
fastcgi_cache_valid any 1m;
fastcgi_cache_min_uses 1;
fastcgi_cache_use_stale error timeout invalid_header http_500 http_503 updating;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
#add_header X-Cache "$upstream_cache_status - $upstream_response_time";
fastcgi_cache_key
"$scheme$request_method$host$request_uri"
|
大概解釋下各個參數的含義:數據庫
fastcgi_cache 該指令用於設置哪一個緩存區將被使用,zone_name的值爲fastcgi_cache_path指令建立的緩存名稱後端
fastcgi_cache_path 做用域:http緩存
1
2
3
4
|
fastcgi_cache_path path
[levels=levels] [use_temp_path=
on
|off] keys_zone=name:size [inactive=time]
[max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time]
[purger=
on
|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
|
該指令用於設置緩存文件的存放路徑,示例以下:fastcgi_cache_path /data/nginx/cache levels=1:2 keys_zone=cache_one:100M inactive=1d max_size=10g; 服務器
a、levels:指定了該緩存空間有兩層hash目錄,設置緩存目錄層數,levels=1:2,表示建立兩層目錄緩存,最多建立三層。第一層目錄名取fastcgi_cache_key md5的最後一個字符,第二層目錄名取倒數2-3字符,如:fastcgi_cache_key md5爲b7f54b2df7773722d382f4809d65029c,則:
1
2
|
levels=1:2爲/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c
levels=1:2:3爲/data/nginx/cache/c/29/650/b7f54b2df7773722d382f4809d65029c
|
b、keys_zone爲這個緩存區起名爲zone_name,500m指代緩存空間爲500MB;
c、inactive=1d 表明若是緩存文件一天內沒有被訪問,則刪除;
d、max_size=30g表明硬盤緩存最大爲30G;
設置緩存多個磁盤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
fastcgi_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m max_size=10g inactive=60m use_temp_path=off;
fastcgi_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m max_size=10g inactive=60m use_temp_path=off;
split_clients $request_uri $my_cache {
50%
"my_cache_hdd1"
;
50%
"my_cache_hdd2"
;
}
server {
...
location / {
fastcgi_cache $my_cache;
}
}
|
將緩存文件放入內存中
編輯/etc/fstab 或者 放入 /dev/shm
1
2
3
|
tmpfs /etc/nginx/cache tmpfs defaults,size=100M 0 0
mount -a
df -ah | grep tmpfs
|
須要注意的是fastcgi_cache緩存是先寫在fastcgi_temp_path再移到fastcgi_cache_path,因此這兩個目錄最好在同一個分區,從0.8.9以後能夠在不一樣的分區,不過仍是建議放同一分區
fastcgi_cache_methods 該指令用於設置緩存哪些HTTP方法,默認緩存HTTP GET/HEAD方法。
fastcgi_cache_min_uses URL通過多少次請求將被緩存
fastcgi_cache_valid reply_code [reply_code ... ] time
該指令用於對不一樣返回狀態碼的URL設置不一樣的緩存時間,例如:
1
2
|
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 404 1m;
|
設置202 302狀態URL緩存10分鐘,404狀態的URL緩存1分鐘。
注意:若是不指定狀態碼,直接指定緩存時間,則只有200,301,302狀態碼會進行緩存。
1
|
fastcgi_cache_valid 5m;
|
any
能夠指定緩存任何響應碼
1
2
3
|
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
|
緩存的參數也能夠在響應頭直接設置。這些的優先級高於緩存時間設定使用該指令
- The 「X-Accel-Expires」 header field sets caching time of a response in seconds. The zero value disables caching for a response. If the value starts with the
@
prefix, it sets an absolute time in seconds since Epoch, up to which the response may be cached. - If the header does not include the 「X-Accel-Expires」 field, parameters of caching may be set in the header fields 「Expires」 or 「Cache-Control」.
- If the header includes the 「Set-Cookie」 field, such a response will not be cached.
- If the header includes the 「Vary」 field with the special value 「
*
」, such a response will not be cached (1.7.7). If the header includes the 「Vary」 field with another value, such a response will be cached taking into account the corresponding request header fields (1.7.7).
fastcgi_cache_key
該指令用來設置Web緩存的Key值,Nginx根據Key值MD5緩存。通常根據host(域名),host(域名),request_uri(請求的路徑)等變量組合成fastcgi_cache_key。
例如:fastcgi_cache_key "schemeschemerequest_methodhosthostrequest_uri";
定義fastcgi_cache的key,示例中就以請求的URI做爲緩存的key,Nginx會取這個key的md5做爲緩存文件,若是設置了緩存哈希目錄,Nginx會從後往前取相應的位數作爲目錄。
注意必定要加上$request_method做爲cache key,不然若是HEAD類型的先請求會致使後面的GET請求返回爲空
fastcgi_temp_path path [level1 [level2 [level3]]]; 默認爲 fastcgi_temp;
該指令用來設置fastcgi_cache臨時文件目錄
1
|
fastcgi_temp_path /spool/nginx/fastcgi_temp 1 2;
|
a temporary file might look like this:
1
|
/spool/nginx/fastcgi_temp/7/45/00000123457
|
fastcgi_cache_use_stale : fastcgi_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_503 | http_403 | http_404 | off ...;
定義哪些狀況下用過時緩存
x-cache頭,用於調試
$upstream_response_time爲過時時間
$upstream_cache_status 變量表示此請求響應來自cache的狀態,幾種狀態分別爲:
- MISS – The response was not found in the cache and so was fetched from an origin server. The response might then have been cached.
- BYPASS – The response was fetched from the origin server instead of served from the cache because the request matched a proxy_cache_bypass directive (see Can I Punch a Hole Through My Cache? below.) The response might then have been cached.
- EXPIRED – The entry in the cache has expired. The response contains fresh content from the origin server.
- STALE – The content is stale because the origin server is not responding correctly, and proxy_cache_use_stale was configured.
- UPDATING – The content is stale because the entry is currently being updated in response to a previous request, and proxy_cache_use_stale updating is configured.
- REVALIDATED – The proxy_cache_revalidate directive was enabled and NGINX verified that the current cached content was still valid (If-Modified-Since or If-None-Match).
- HIT – The response contains valid, fresh content direct from the cache.
有一些狀況會影響到cache的命中 這裏須要特別注意
- Nginx fastcgi_cache在緩存後端fastcgi響應時,當響應裏包含「set-cookie」時,不緩存;
- 當響應頭包含Expires時,若是過時時間大於當前服務器時間,則nginx_cache會緩存該響應,不然,則不緩存;
- 當響應頭包含Cache-Control時,若是Cache-Control參數值爲no-cache、no-store、private中任意一個時,則不緩存,若是Cache-Control參數值爲max-age時,會被緩存,且nginx設置的cache的過時時間,就是系統當前時間 + mag-age的值。
1
2
3
4
5
6
7
8
|
header(
"Expires: "
.gmdate(
"D, d M Y H:i:s"
, time()+10000).
' GMT'
);
header(
"Expires: "
.gmdate(
"D, d M Y H:i:s"
, time()-99999).
' GMT'
);
header(
"X-Accel-Expires:5"
);
// 5s
header(
"Cache-Control: no-cache"
);
//no cache
header(
"Cache-Control: no-store"
);
//no cache
header(
"Cache-Control: private"
);
//no cache
header(
"Cache-Control: max-age=10"
);
//cache 10s
setcookie(
'hello'
,
"testaaaa"
);
//no cache
|
注意session使用的時候有坑,能夠用下面來設置
1
2
3
|
session_cache_limiter(
"none"
);
session_start();
echo date(
"Y-m-d H:i:s"
,time());
|
能夠看一下PHP源代碼中的頭信息 Expires等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
//ext/session/session.c line:1190 左右
// ...
CACHE_LIMITER_FUNC(
private
)
/* {{{ */
{
ADD_HEADER(
"Expires: Thu, 19 Nov 1981 08:52:00 GMT"
);
CACHE_LIMITER(private_no_expire)(TSRMLS_C);
}
/* }}} */
//再到這裏3 或者上面幾個 ##默認是nocache
CACHE_LIMITER_FUNC(nocache)
/* {{{ */
{
ADD_HEADER(
"Expires: Thu, 19 Nov 1981 08:52:00 GMT"
);
/* For HTTP/1.1 conforming clients and the rest (MSIE 5) */
ADD_HEADER(
"Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
);
/* For HTTP/1.0 conforming clients */
ADD_HEADER(
"Pragma: no-cache"
);
}
/* }}} */
//這裏2
static
php_session_cache_limiter_t php_session_cache_limiters[] = {
CACHE_LIMITER_ENTRY(
public
)
CACHE_LIMITER_ENTRY(
private
)
CACHE_LIMITER_ENTRY(private_no_expire)
CACHE_LIMITER_ENTRY(nocache)
{0}
};
static
int
php_session_cache_limiter(TSRMLS_D)
/* {{{ */
{
php_session_cache_limiter_t *lim;
if
(PS(cache_limiter)[0] ==
'\0'
)
return
0;
if
(SG(headers_sent)) {
const
char
*output_start_filename = php_output_get_start_filename(TSRMLS_C);
int
output_start_lineno = php_output_get_start_lineno(TSRMLS_C);
if
(output_start_filename) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Cannot send session cache limiter - headers already sent (output started at %s:%d)"
, output_start_filename, output_start_lineno);
}
else
{
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Cannot send session cache limiter - headers already sent"
);
}
return
-2;
}
for
(lim = php_session_cache_limiters; lim->name; lim++) {
if
(!strcasecmp(lim->name, PS(cache_limiter))) {
lim->func(TSRMLS_C);
//這裏1
return
0;
}
}
return
-1;
}
|
3、清除緩存
NGINX只在商業版中支持proxy_cache_purge指令清除緩存,開源的ngx_cache_purge模塊只支持單一key的緩存清除。爲了實現按目錄清除緩存只能本身開發。
NGINX做爲Cache服務器時將資源內容以文件形式進行緩存,緩存元信息存儲於共享內存中,組織成一棵紅黑樹。紅黑樹中的每一個節點表明一個Cache元信息。NGINX將Cache Key的HASH值做爲紅黑樹節點的KEY。內容緩存文件以該HASH值做爲文件名存儲在磁盤上。
NGINX的處理流程簡化描述是這樣的:當請求到達時,根據Cache Key的HASH值在紅黑樹中進行查找。若是找到,並查看相關信息,若是Cache可用,返回相應的Cache文件。不然,則回源抓取。
由於元信息是以Cache Key的HASH值做爲Key存儲的,於是紅黑樹中並不能保留Cache Key中有層級關係. 如」/uri/foo」和」/uri/bar」在元信息紅黑樹中徹底沒有關係。要實現按照目錄清除緩存,須要將Cache Key中層次關係存儲起來。
能夠這樣作,在共享內存中創建一棵目錄樹來存儲層級關係。將Cache Key類比於文件系統中的路徑, 每級路徑存儲爲樹中的一個節點。當須要清除某一目錄下的全部緩存時,將該節點子樹的中的全部緩存清除便可。
安裝Purge模塊
Purge模塊被用來清除緩存
1
2
|
wget http:
//labs.frickle.com/files/ngx_cache_purge-1.2.tar.gz
tar -zxvf ngx_cache_purge-1.2.tar.gz
|
編譯
1
2
3
4
|
./configure \
…… \
--with-http_geoip_module \
--add-module=/usr/local/ngx_cache_purge-1.2
|
4、須要注意的一些問題
設置了以後重啓nginx就能夠生效了,這個時候再訪問php的頁面的話,就會被緩存了,能夠查看/var/logs/nginx/fastcgi_cache_dir這個目錄下面是有緩存文件的。最後再說明一點,若是更改了緩存目錄的路徑,必定要把緩存的名稱也改掉,後端調用的名稱也同步改掉,若是隻改掉了緩存目錄,不改緩存名稱的話,緩存的時候仍是會緩存到以前的路徑下面去,可是調用的時候調用的是新的路徑,這個時候就會出現找不到的狀況
參考文章
http://www.nginxtips.com/configure-nginx-fastcgi-cache/
http://www.haidx.com/fastcgi-cache-details.html
http://www.just4coding.com/blog/2014/11/01/nginx-purge-directory/
http://weizhifeng.net/nginx-proxy-cache.html
https://www.nginx.com/blog/nginx-caching-guide/#gs.6PdbraI
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache
https://www.cnxct.com/several-reminder-in-nginx-fastcgi_cache-and-php-session_cache_limiter/
https://rtcamp.com/wordpress-nginx/tutorials/single-site/fastcgi-cache-with-purging/
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache