1.Nginx的缓存简介
nginx的http_proxy模块,可以实现类似于Squid的缓存功能。Nginx对客户已经访问过的内容在Nginx服务器本地建立副本,这样在一段时间内再次访问该数据,就不需要通过Nginx服务器再次向后端服务器发出请求,所以能够减少Nginx服务器与后端服务器之间的网络流量,减轻网络拥塞,同时还能减小数据传输延迟,提高用户访问速度。同时,当后端服务器宕机时,Nginx服务器上的副本资源还能够回应相关的用户请求,这样能够提高后端服务器的鲁棒性。
2.nginx cache的最基本的配置
nginx.conf
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;//忽略header设置这些值的内容
fastcgi_temp_path /tmp/nginx/fcgi/temp;
vhost配置
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";
#这里cache_key可能有多种设定:
#商品详情页的cache的key:self.busMethod .. '-' .. productId .. '-' .. #apiVersion
#商品列表页面的cache key:self.busMethod .. '-' .. shopId .. '-' .. listType .. '-' .. cId .. '-' .. sort .. '-' .. page .. '-' .. pageSize
#店铺商品列表接口cache key:self.busMethod .. '-' .. shopId
#商品评论的列表接口 cache key:self.busMethod .. '-' .. productId .. '-' .. rateType .. '-' .. version .. '-' .. page .. '-' .. pageSize
#推广领券页接口 cache key;self.busMethod .. '-' .. couponId .. '-' .. productId
#cache purge
#$1是cache_zone $2是cache_key
location ~ /purge/(.*)/(.*) {
#allow 127.0.0.1;
#allow 10.40.0.0/16;
#deny all;
fastcgi_cache_purge $1 $2;
}
}
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配置
#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
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,则:
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;
设置缓存多个磁盘
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
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
为不同的HTTP返回状态码的资源设置不同的缓存时长。
该指令用于对不同返回状态码的URL设置不同的缓存时间,例如:
proxy_cache_valid 200 302 10m; #为响应码是200和302的资源,设置缓存时长为10分钟
proxy_cache_valid 404 1m; #为响应码是404的资源,设置的缓存的时长为1分钟
注意:如果不指定状态码,直接指定缓存时间,则只有200,301,302状态码会进行缓存。fastcgi_cache_valid 5m;
any 可以指定缓存任何响应码
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
缓存的参数也可以在响应头
直接设置。这些的优先级高于缓存时间设定使用该指令.
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使用的时候有坑,可以用下面来设置
session_cache_limiter("none");
session_start();
echo date("Y-m-d H:i:s",time());
fastcgi_cache_key
该指令用来设置Web缓存的Key值,Nginx根据Key值MD5缓存。一般根据host(域名),request_uri(请求的路径)等变量组合成fastcgi_cache_key。
例如:fastcgi_cache_key "schemerequest_methodhostrequest_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临时文件目录
fastcgi_temp_path /spool/nginx/fastcgi_temp 1 2;
a temporary file might look like this:
/spool/nginx/fastcgi_temp/7/45/00000123457
proxy_cache_use_stale
增强站点容错能力,源站有问题时,nginx可以通过proxy_cache_use_stale指令开启容错能力,即使用缓存内容来响应客户端的请求。举个栗子:
location / {
...
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
}
如上配置表示,当作为cache的NGINX收到源站返回error、timeout或者其他指定的5XX错误,并且在其缓存中有请求文件的陈旧版本,则会将这些陈旧版本的文件而不是错误信息发送给客户端。
x-cache
头,用于调试
$upstream_response_time为过期时间
缓存命中情况的Nginx变量$upstream_cache_status,表示此请求响应来自cache的状态,几种状态分别为:
MISS
—— 响应在缓存中找不到,所以需要在服务器中取得。这个响应之后可能会被缓存起来
BYPASS
—— 响应来自原始服务器而不是缓存,因为请求匹配了一个proxy_cache_bypass,这个响应之后可能会被缓存起来
EXPIRED
—— 缓存中的某一项过期了,来自原始服务器的响应包含最新的内容
STALE
—— 内容陈旧是因为原始服务器不能正确响应。需要配置proxy_cache_use_stale
UPDATING
—— 内容过期了,因为相对于之前的请求,响应的入口(entry)已经更新,并且proxy_cache_use_stale的updating已被设置
REVALIDATED
—— proxy_cache_revalidate命令被启用,NGINX检测得知当前的缓存内容依然有效(If-Modified-Since或者If-None-Match)
HIT
—— 响应包含来自缓存的最新有效的内容
http响应头Cache-Control,当在响应头部中Cache-Control被配置为Private,No-Cache,No-Store或者Set-Cookie,不允许代理对资源进行缓存。
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模块被用来清除缓存:
wget http://labs.frickle.com/files/ngx_cache_purge-1.2.tar.gz
tar -zxvf ngx_cache_purge-1.2.tar.gz
编译
./configure \
…… \
--with-http_geoip_module \
--add-module=/usr/local/ngx_cache_purge-1.2
- 需要注意的一些问题
设置了之后重启nginx就可以生效了,这个时候再访问php的页面的话,就会被缓存了,可以查看/var/logs/nginx/fastcgi_cache_dir这个目录下面是有缓存文件的。最后再说明一点,如果更改了缓存目录的路径,一定要把缓存的名称也改掉,后端调用的名称也同步改掉,如果只改掉了缓存目录,不改缓存名称的话,缓存的时候还是会缓存到之前的路径下面去,但是调用的时候调用的是新的路径,这个时候就会出现找不到的情况。