一、简介
Nginx版本从0.7.48开始,支持了类似Squid的缓存功能。这个缓存是把URL及相关组合当做Key,用Md5算法对Key进行哈希,得到硬盘上对应的哈希目录路径,从而将缓存内容保存在该目录内。
Nginx Web 缓存服务只能为指定URL或状态码设置过期时间,不支持类似Squid的PURGE指令手动清除缓存;但是我们可以通过Nginx的模块ngx_cache_purge清除指定URL的缓存。
- proxy_cache:缓存后端服务器的内容,可能是任何内容,包括静态的和动态,减少了nginx与后端通信的次数,节省了传输时间和后端宽带
- fastcgi_cache:缓存fastcgi生成的内容,很多情况是php生成的动态的内容,少了nginx与php的通信的次数,更减轻了php和数据库(mysql)的压力,这比用memcached之类的缓存要轻松得多
图片来自网络
二、配置
nginx.conf
代码语言:javascript复制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配置
代码语言:javascript复制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配置
代码语言:javascript复制#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
代码语言:javascript复制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,则:
代码语言:javascript复制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;
设置缓存多个磁盘
代码语言:javascript复制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
代码语言:javascript复制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设置不同的缓存时间,例如:
代码语言:javascript复制fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 404 1m;
设置202 302状态URL缓存10分钟,404状态的URL缓存1分钟。
注意:如果不指定状态码,直接指定缓存时间,则只有200,301,302状态码会进行缓存。
代码语言:javascript复制fastcgi_cache_valid 5m;
any
可以指定缓存任何响应码
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临时文件目录
代码语言:javascript复制fastcgi_temp_path /spool/nginx/fastcgi_temp 1 2;
a temporary file might look like this:
代码语言:javascript复制/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的值。
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使用的时候有坑,可以用下面来设置
代码语言:javascript复制session_cache_limiter("none");
session_start();
echo date("Y-m-d H:i:s",time());
可以看一下PHP源代码中的头信息 Expires等
代码语言:javascript复制//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] == '