nginx 的缓存和清理

邱秋 • 2020年05月22日 • 阅读:12329 • nginx

背景

由于服务器的各方面配置都太低,经不起消耗,所以基本上所有动态的内容都以缓存形式展现,除了部分的交互使用动态意外。

但是每次修改了动态的内容,缓存有没过期,这样得必须手动清理缓存了。于是尝试使用 nginx + ngx_cache_purge 模块

如何清理缓存

目前官方的Nginx Web缓存服务只能为指定URL或状态码设置过期时间,不支持类似Squid的PURGE指令,手动清除指定缓存页面,但是,通过一个第三方的Nginx ngx_cache_purge 模块,可以清除指定URL的缓存。

ngx_cache_purge 模块的安装

检查是否安装

nginx -V   #大写的V

看到如下:

nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

安装

因为已经安装过 nginx,所以无法 ./configure

nginx -v  #小写的V

查看版本

nginx version: nginx/1.18.0

官网 上找对对应的版本, down 下来, 解压

wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar -zxvf nginx-1.18.0.tar.gz

这里 找到 ngx_cache_purge 的最新版本, down 下来, 解压

wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
tar -zxvf ngx_cache_purge-2.3.tar.gz

备份启动文件

cp /sbin/nginx /sbin/nginx.bak

重新编译刚才下载的 nginx 把模块带进去编译

cd nginx-1.18.0 #第一步
# ./configure + nginx -V  看到的 configure arguments + '--add-module=/usr/software/ngx_cache_purge-2.3'
./configure --prefix=/etc/nginx (略) --add-module=/root/app/ngx_cache_purge-2.3  #第二步
make  #第三步

是 make 编译, 不是 make install ,make install 会覆盖原来已经安装好的内容。编译必须没有错误,才能继续下一步

检查是否编译成功

./objs/nginx -V

如果编译成功,把 objs 下的 nginx 文件 拷贝到 /sbin 目录下,然后检查是否正常

/sbin/nginx -V

重启

/sbin/nginx -c /etc/nginx/nginx.conf
/sbin/nginx -s reload

检查下进程,正常会看到 多出的 2 个进程

ps -ef|grep nginx
root      9266     1  0 17:08 ?        00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
root      9267  9266  0 17:08 ?        00:00:00 nginx: worker process
root      9268  9266  0 17:08 ?        00:00:00 nginx: cache manager process  #多出的
root      9269  9266  0 17:08 ?        00:00:00 nginx: cache loader process  #多出的
root      9272  1261  0 17:08 pts/0    00:00:00 grep --color=auto nginx

没有的话, kill 进程,然后重启

缓存的配置

缓存位置

配置缓存位置,才可能定位清理。通过 proxy_cache_path 指定 缓存位置 修改/etc/nginx/nginx.conf 的 http

worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
http {
  ....
  proxy_cache_path /etc/nginx/cache levels=1:2 keys_zone=web_cache:10m max_size=10g;
  proxy_temp_path /etc/nginx/cache; #缓存临时目录
  ....
}

其中/etc/nginx/cache 为缓存位置,web_cache为缓存名称 ,10m为缓存单位,10g 为最大单位

指定server 配置,修改 server

server {
   listen 80;
   proxy_cache web_cache; #就是keys_zone的值
   .....
}

缓存等级

比如有一个URL是 http://chuchur.com/1.png,那么这个图片如果被缓存那他的路径就是 /etc/nginx/cache/9/ad/e0bd86606797639426a92306b1b98ad9, level=1:2就是把最后一位数9拿出来建一个目录,然后再把9前面的2位建一个目录,最后把刚才得到的这个缓存文件放到9/ad目录中。

同样的方法推理,如果配置level=1:1,那么缓存文件的路径就是/etc/nginx/cache/9/d/e0bd86606797639426a92306b1b98ad9

  • MD5哈希过之后的路径是十六进制的,对于nignx来说查询速度更快;
  • level=1:2会比level=1:1建立更多的目录,适合缓存海量文件,因为单个目录下的文件太多会降低IO性能; 如果带参数呢?
  • 缓存会先被写入写入临时文件,所以建议proxy_cache_path和proxy_temp_path放在同一个文件系统当中,避免不通文件系统之间的磁盘IO消耗; 比如http://chuchur.com/1.pngv=1,那么缓存路径还是一样吗? 这个具体要看 缓存key的 配置

缓存key

Nginx默认会缓存所有get和head方法的请求结果,缓存的key默认使用请求字符串。 自定义key

proxy_cache_key $host$uri;
proxy_cache_key $host$uri$is_args$args;

第一个配置只根据不带参的$uri进行哈希,所以这时候加了参数和没加参数是一样的结果;

第二个配置就是把域名之后所有的内容(也就是$request_uri)都进行哈希。

所以生成的缓存目录不一样

缓存次数

指定请求至少被发送了多少次以上时才缓存,可以防止低频请求被缓存。

proxy_cache_min_uses 5;

缓存方法

指定哪些方法的请求被缓存

proxy_cache_methods GET HEAD POST;

缓存有效期

默认情况下,缓存内容是长期存留的,除非缓存的总量超出限制。可以指定缓存有效时间 所有内容缓存300天

proxy_cache_valid any 300d;  

缓存状态码

响应状态码为200,302时,10分钟有效

proxy_cache_valid 200 302 10m;

缓存过滤

对于某些请求,是否可以不走缓存? proxy_cache_bypass: 该指令响应来自原始服务器而不是缓存。

proxy_cache_bypass $cookie_nocache $arg_nocache$airg_comment;

缓存的清理

关于 nginx 的更多设置请看 这篇

清理缓存配置

location ~ /clear_cache(/.*) {
    #删除指定缓存区域cache_one的特定缓存文件$1$is_args$args
    proxy_cache_purge web_cache $1$is_args$args;
    #运行本机和10.0.217.0网段的机器访问,拒绝其它所有
    allow           127.0.0.1;
    allow           10.0.217.0/24;
    deny          all;
}

这样清理某个缓存文件的时候地址前面加上 /clear_cache 即可,如 :清理 文件 https://www.chuchur.com/js/a.js,输入 https://www.chuchur.com/clear_cache/js/a.js, 看到 Successful purge 表明清理成功。

可以每次修改动态内容之后,自动触发 缓存清理器操作

完整的例子

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    charset  utf-8;

    #注:proxy_temp_path和proxy_cache_path指定的路径因该在同一分区
    proxy_temp_path   /etc/nginx/proxy_temp_dir;
    proxy_cache_path  /etc/nginx/proxy_cache_dir levels=1:2 keys_zone=cache_one:200m inactive=1d max_size=10g;

    server {
        listen       80;
        server_name  chuchur.com;
        location / {
            root   html;
            index  index.html index.htm;
        }

        #用于清除缓存
        location ~ /clear_cache(/.*) {
            #设置只允许指定的IP或IP段才可以清除URL缓存。
            allow   127.0.0.1;
            allow   192.168.1.0/16;
            deny        all;
            proxy_cache_purge cache_one $host$1$is_args$args;
        }

        location ~ \.(gif|jpg|jpeg|png|bmp|ico)$ {
            proxy_next_upstream http_502 http_504 error timeout invalid_header;
            proxy_cache cache_one;
            #对不同的HTTP状态码设置不同的缓存时间
            proxy_cache_valid 200 304 12h;
            #以域名、URI、参数组合成Web缓存的Key值,Nginx根据Key值哈希,存储缓存内容到二级缓存目录内
            proxy_cache_key $host$uri$is_args$args; 
            proxy_set_header Host  $host;
            proxy_set_header X-Forwarded-For  $remote_addr;
            proxy_pass http://127.0.0.1:8080;
            #缓存时间           
            expires 7d; 
        }
    }
}

一些问题

该缓存的没缓存, 不该缓存的缓存了。

排除问题

add_header      Nginx-Cache     "$upstream_cache_status";

查看Headers 里的 Nginx-Cache 状态 是 Hit 还是 Miss

允许 一些头部信息:

proxy_ignore_headers Expires;
proxy_ignore_headers Cache-Control;

控制哪些缓存, 哪些不缓存:

set $nocache 0;
# 以 aaa,bbb,ccc 开头的不缓存
if ($request_uri ~ ^/(aaa|bbb|ccc)) {
    set $nocache 1;
}

proxy_cache_bypass $nocache;

# cookie 里面设置了nocache,或者 参数传值里有aaa,bbb 的不缓存,满足一个即可

proxy_no_cache $cookie_nocache $arg_aaa $arg_bbb;

为什么明明设置了不缓存 Nginx-Cache 状态也是 BYPASS, 拿到的还是缓存信息?

一般都是 get 请求 ,post 请求不会缓存数据

通过Network => Size 观察 ,居然是 (memory cache) ,也就是 ,浏览器直接从内存取的数据, 未从服务器获取最新数据

解决: 在 get 请求时传递随机字符串 :

var time = Date.now();
$.get("/aaa/bbb/ccc?time=" + time);

至此缓存和不缓存,已经缓存的自动更新的问题顺利解决。

我,秦始皇,打钱!

相关文章

禅境花园小程序

关注前沿技术开发.