问题描述
有两台服务器,一台是外网的网关服务器,一台是内网的资源服务器,但是两台服务器距离很远(跨省),页面中依赖大量插件资源,加载耗时久,本章重点讲解Nginx代理缓存静态资源。
解决思路
- CDN
- 开启gzip压缩
- 图片格式优化,找到大图片
- 外网服务器进行静态资源缓存
proxy_cache工作原理
Nginx 的 proxy_cache 模块允许 Nginx 作为反向代理服务器时缓存后端服务器的响应。以下是 proxy_cache 模块的工作原理:
- 请求到达:客户端向 Nginx 发送请求。
- 缓存查找:Nginx 首先检查请求是否命中缓存。这是通过查找共享内存中的缓存键(由 proxy_cache_key 定义)来完成的。
- 缓存命中:如果请求命中缓存,Nginx 直接从缓存中读取响应并返回给客户端。
- 缓存未命中:如果请求未命中缓存,Nginx 将请求转发到后端服务器。
- 后端响应:后端服务器处理请求并返回响应给 Nginx。
- 缓存存储:Nginx 将后端服务器的响应存储在本地文件系统中,同时在共享内存中更新缓存键和元数据。
- 返回响应:Nginx 将后端服务器的响应返回给客户端,并根据 proxy_cache_valid 指令设置的规则决定缓存时间。
配置
# 设置日志格式,$upstream_cache_status代表是否命中缓存
# $upstream_cache_status的返回值有7个:
# HIT表示缓存命中
# MISS表示未命中,请求被传送到后端
# EXPIRED表示缓存已经过期,请求被传送到后端
# UPDATING表示正在更新缓存,将使用旧的应答
# STALE表示无法从后端服务器更新缓存时,返回了旧的缓存内容
# BYPASS表示缓存被绕过了
# REVALIDATED表示启用proxy_cache_revalidate指令后,当缓存内容过期时,Nginx通过一次If-Modified-Since的请求头去验证缓存内容是否过期,此时会返回该状态
log_format main '$remote_addr - $remote_user [$request_time] [$time_local] "$request" '
'$upstream_cache_status '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 打开日志格式化功能,如果这里不打开的话,上面的格式化不生效
access_log logs/access.log main;
# 设置缓存区信息
# levels:指定该缓存空间对应的目录,最多可以设置3层,每层取值为1|2;例如:levels=1:2 缓存空间有两层目录,第一次是1个字母,第二次是2个字母
proxy_cache_path /app/nginx/js_cache levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
# --------------以下为server中的配置---------------
location / {
proxy_pass http://ip:端口;
}
# 启用缓存
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ioc|ico|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma|css|js)$ {
proxy_pass http://ip:端口;
proxy_cache my_cache;
# proxy_cache_valid设置不同响应码的缓存过期时间
# HTTP 206 Partial Content(部分内容)状态码表示服务器成功处理了客户端请求资源部分内容的GET请求,主要应用于支持范围请求(Range Request)的场景,比如文件断点下载
proxy_cache_valid 200 304 206 60m; # 缓存200, 304, 206响应3600秒(1小时)
proxy_cache_key $uri; # 缓存键的生成方式
# add_header X-Cache '$upstream_cache_status from $host'; # 在请求的http响应头中返回,判断是否命中缓存
}
proxy_cache_path与proxy_cache_valid中超时时间同时设置,生效控制问题
inactive时间到了,数据删除。proxy_cache_valid时间到了不会被删除,但是会认为失效,再次请求时会重新下载。有请求,inactive就刷新计时,valid不变。没请求,inactive和valid都不变。
分析各种情况:
inactive设置1m,valid设置1h
首先,请求进来,cache出现,两个时间开始倒计时。
情况一:不断请求这个cache,inactive不断刷新1m倒计时,直到到达1h,valid过期。这时你去请求了一次,nginx重新去读取服务器数据,刷新valid倒计时。期间数据一直在缓存里。不请求,就再过1m删掉。
情况二:两次请求间隔超过了1min,inactive生效,删除了这个cache数据,没了。你再请求,相当于重新去服务器拿了一次数据,inactive和valid倒计时都会重新刷新,不请求,cache里就没有这份数据了inactive设置1m,valid设置1m
首先,请求进来,cache出现,两个时间开始倒计时。
情况一:1m内不请求,最后inactive生效删掉。不请求就没缓存了,请求了一次,重新从服务器读取一份,两个计时刷新。
情况二:1m内请求了一次,inactive时间刷新,但是valid还在计时,所以1m到了后,缓存过期了。你再请求就重新从服务器读取一份,刷新计时。不请求,就等待1m,由inactive生效删除了缓存inactive设置1h,valid设置了1m
首先,请求进来,cache出现,两个时间开始倒计时。
过了1m,缓存过期,数据在没删掉。不请求,直到1h到,inactive删掉缓存。请求了一次,重新从服务器读取,刷新两个计时。
所以,通常inactive应该需要设置的比valid中时间长,inactive和valid是配合使用,不是谁时间短覆盖谁的关系。
缓存清理
清除缓存,直接删除缓存文件夹,下次请求的时候会重新生成
外网缓存失败,内网不允许缓存
在生产环境出现过一个问题,在外网服务器nginx配置了缓存信息,日志配置生效,缓存目录也生成,但是始终没有生成缓存文件,最后排查发现,在内网的nginx配置了如下禁止缓存的信息,应该将此段内容从内网服务器移到外网上或者使用proxy_ignore_headers
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
add_header Pragma no-cache;
add_header Expires 0;
private:专用于个人的缓存,中间代理、CDN 等不能缓存此响应
public:响应可以被中间代理、CDN 等缓存
参考
nginx proxy_cache缓存详解(强烈推荐)
nginx配置proxy_cache_path之inactive和proxy_cache_valid对比
Nginx 缓存系统 proxy_cache详解