Nginx 静态缓存加速
前言
大家好,今天想跟你们聊聊 Nginx 静态缓存这个话题。其实这已经是个老生常谈的内容了,但我发现很多同学在实际项目中还是没有用好它,导致网站加载速度慢,用户体验差。每次看到这种情况我就手痒痒,想把优化思路整理出来分享给大家。
静态资源加速这事儿说简单也简单,说复杂也复杂。简单在于 Nginx 本身就提供了很强大的缓存机制,配几个参数就能见效;复杂在于要真正用好它,需要理解缓存的整个生命周期、缓存失效策略以及如何结合业务场景做调优。咱们今天就从头到尾把这事儿说清楚。
什么是静态缓存
先说说概念吧。静态缓存其实就是把那些不经常变化的资源,比如图片、CSS、JS 文件、字体等,直接放在内存或者磁盘里。当用户访问的时候,Nginx 直接从缓存里读取,不需要每次都去后端应用服务器请求一遍。
你想啊,如果没有缓存,用户每次打开页面,浏览器都要去找后端服务器要这些静态文件。后端服务器就得从磁盘读取文件,再返回给用户。这一来一回,不仅增加了响应时间,还加重了后端服务器的负担。特别是流量大的时候,后端服务器可能就被这些静态请求给拖垮了。
有了缓存之后呢?Nginx 变成了一个"二道贩子",第一次从后端拿到资源后,就自己存一份。下次再有用户来要同样的资源,Nginx 直接从自己的"仓库"里拿,速度当然快多了。
Nginx 缓存的基本配置
好了,概念说完,咱们来看看具体怎么配。先来看一个最基础的缓存配置:
http {
# 定义缓存区域
proxy_cache_path /tmp/nginx_cache
levels=1:2
keys_zone=static_cache:10m
max_size=100m
inactive=60m
use_temp_path=off;
server {
location /static/ {
# 启用缓存
proxy_cache static_cache;
# 缓存的 HTTP 状态码
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
# 缓存的 Key
proxy_cache_key "$scheme$request_method$host$request_uri";
# 设置响应头,告诉浏览器缓存多久
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://backend_server;
}
}
}
这段配置看起来有点多,我来解释一下几个关键的参数。
proxy_cache_path 用来定义缓存存放的位置和规则。levels=1:2 表示缓存目录的层级,这样可以让文件分布更均匀。keys_zone=static_cache:10m 给缓存区域起了个名字,并分配 10MB 的内存来存储缓存的元数据。max_size=100m 则是磁盘缓存的最大上限。inactive=60m 很有意思,表示如果一个文件 60 分钟内没人访问,就自动从缓存里删掉,即使它还没过期。
proxy_cache_valid 用来指定不同状态码的缓存时间。这里我们让 200 和 302 响应缓存 10 分钟,404 响应缓存 1 分钟。
缓存命中与未命中
在实际使用中,我们经常需要知道某个请求是命中了缓存还是没命中。Nginx 提供了一个变量 $upstream_cache_status,可以帮我们判断。
这个变量有几个常见的值:HIT 表示命中缓存,MISS 表示未命中,BYPASS 表示绕过缓存,EXPIRED 表示缓存已过期,STALE 表示使用了过期缓存。
我们可以通过添加响应头的方式,把这个状态返回给前端,这样在调试的时候就能很清楚地看到缓存的情况了:
add_header X-Cache-Status $upstream_cache_status;
打开浏览器的开发者工具,刷新几次页面,你会看到第一次是 MISS,后面几次就变成 HIT 了。那一刻的成就感,懂的都懂。
浏览器端缓存配合
其实啊,Nginx 缓存只是整个缓存链路的一环。要让速度飞起来,还得配合浏览器端的缓存一起使用。
你想啊,如果用户的浏览器已经缓存了 CSS 和 JS 文件,那他根本就不会向 Nginx 发起请求,响应时间接近于零。所以我们在 Nginx 这一端设置的缓存策略,也要考虑到浏览器的缓存行为。
location /static/ {
proxy_cache static_cache;
proxy_cache_valid 200 7d; # 缓存 7 天
# 设置浏览器端的缓存时间
expires 7d;
add_header Cache-Control "public, max-age=604800";
proxy_pass http://backend_server;
}
这里 expires 指令会自动添加 Expires 响应头,告诉浏览器这个资源可以缓存多久。Cache-Control 头则更现代一些,max-age 表示缓存的秒数,public 表示可以被 CDN 和浏览器缓存。
不过要注意一点,设置这么长的缓存时间后,如果你的静态资源有更新,用户可能看不到变化。解决这个问题有两个办法:一是给文件名加哈希值,比如 style.a1b2c3.css,这样文件内容变了名字就变了,浏览器会当作新资源重新加载;二是使用 proxy_cache_revalidate 指令,让 Nginx 向后端发送条件请求,检查文件是否有更新。
缓存清理与更新策略
说到缓存清理,这可能是大家最头疼的问题了。缓存一旦设好了,想让它立即失效就没那么简单。
第一种办法是手动删除缓存文件。你可以直接删除 /tmp/nginx_cache 目录下的文件,或者用 rm -rf 清空整个缓存目录。不过这种办法比较暴力,生产环境慎用。
第二种办法是使用 Nginx 的缓存清理模块。不过这个模块默认是没有编译进去的,需要在编译 Nginx 的时候加上 --with-http_proxy_cache_purge 参数。配置如下:
location /purge/ {
proxy_cache_purge static_cache "$scheme$request_method$host$request_uri";
}
这样你就可以通过访问 /purge/static/css/style.css 来清理特定文件的缓存了。
第三种办法是给缓存 key 加上版本号或者时间戳。比如把缓存 key 从 $scheme$request_method$host$request_uri 改成 $scheme$request_method$host$request_uri$vary_version,修改 vair_version 的值就能生成新的缓存。这种方式更加可控,推荐在生产环境使用。
性能优化小技巧
最后再说几个能进一步提升性能的技巧。
第一个是开启缓存的合并请求。如果你有多个小文件,可以考虑把它们合并成一个大文件,减少 HTTP 请求的数量。Nginx 的 concat 模块可以帮你做到这一点:
location /concat/ {
concat on;
concat_max_files 10;
}
这样你就可以通过 /concat/css/style1.css,style2.css,style3.css 的方式一次请求多个文件了。
第二个是启用 gzip 压缩。静态资源压缩后体积能减小 70% 左右,传输时间自然就短了:
gzip on;
gzip_types text/plain text/css application/javascript image/svg+xml;
gzip_min_length 1024;
第三个是把热点数据放在内存缓存里。如果你有特别热门的静态资源,可以考虑用 open_file_cache 把它们缓存到内存中:
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
这样 Nginx 会把文件的元数据缓存在内存里,减少磁盘 IO 操作。
总结
好了,今天关于 Nginx 静态缓存的内容就聊到这里。总结一下几个要点:第一,静态缓存能大幅提升网站性能,减轻后端压力;第二,配置的时候要注意缓存时间、缓存 key 和清理策略;第三,要配合浏览器缓存一起使用;第四,可以根据实际需求使用缓存清理模块和性能优化技巧。
其实缓存这个话题还有很多可以深挖的地方,比如和 CDN 配合、比如动静分离的架构设计、比如如何监控缓存命中率等等。如果大家感兴趣,后面可以再聊聊这些内容。
希望这篇文章对你有帮助,如果觉得有用的话,点个赞再走呗?我们下期再见!
Nginx 静态缓存加速
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法