首页  /  Nginx 进阶  /  正文

CDN 与 Nginx 代理缓存深入

Nginx 进阶 2026-10-02📖 14 分钟👁 —
🚀 Nginx 水平扩展与优化第 8 / 8 页12345678📖 完整导航 →

关于缓存的部分之前已经了解的差不多了,这里是和业务架构强相关的配置参数,需要用到的时候结合具体场景微调,而且很多很难记,不必真的“深入”,仅作了解。

CDN

CDN 都是买的 CDN 云服务商的产品,不做实操演示。

CDN = 内容分发网络,用户就近访问边缘节点,节点缓存内容,未命中回源到 Nginx

CDN 厂商控制台里的应用场景介绍,视频直播、网页站点加速等

用户 → DNS 解析 → 智能 DNS 返回最近的 CDN 节点 IP → 用户就近访问 → CDN 命中直接返回,未命中回源拉取

用户访问域名到 DNS 返回最近节点、再回源的链路

反向代理缓存 proxy_cache 配置

浏览器第一次请求 index.html
  ↓
Nginx 检查自己有没有缓存 → 没有 (MISS)
  ↓
去后端拉数据
  ↓
Nginx 缓存一份到磁盘 + 返回给浏览器 + 附带 Cache-Control 头
  ↓
浏览器缓存一份到本地

浏览器第二次请求时:浏览器发现本地有缓存,直接不向 Nginx 发请求,Nginx 的缓存层根本不会被触发

Nginx 第二次收到不同浏览器的请求时:Nginx 发现磁盘有缓存 (HIT),直接返回,不给浏览器发 Cache-Control 头

这个参数是 nginx 原生支持的。

先不管 keepalive、浏览器缓存、动静分离等配置,只配置 proxy_cache 看效果。

只配了 proxy_cache、还没配过期时间时的 location 内容
etag、if_modified_since、cache-control、expires 混在一起的 location 配置

此时没有多余的请求标头。

在 nginx 本地缓存的流程图:

请求进 Nginx 走磁盘缓存,再到 Tomcat 和 redis、db 的链路

这是最终想要实现的效果。

配置的时候,先在 nginx.conf 的 http 块定义缓存路径和规则,然后在 server、location 启用缓存。

先看效果,下面边配置边解释参数。

#代理缓存配置
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=test_cache:100m  inactive=1d max_size=10g;

在默认站点 location 块配置:

location / {
    proxy_pass http://httpget;
    add_header Content-Type "text/html; charset=utf-8";

    #向上游
    #proxy_http_version 1.1;
    #proxy_set_header Connection "";

    #代理缓存配置
    add_header Nginx-Cache "$upstream_cache_status";
    proxy_cache test_cache;

    }

控制台查看:

响应头里的 Nginx-Cache 是 MISS

这个状态代表缓存没有生效。

我们可以去缓存目录查看是否有缓存。

在 http 块配置的目录是用来存放临时静态文件的。

ls -alh /var/cache 里能看到 nginx 目录
ls -alh /var/cache/nginx 目录下是空的

进去查看,什么也没有,原因就是少了一个配置:缓存过期时间。

其中 http 的 inactive=1d 是当前目录临时文件的存放时间,不是过期时间。

过期时间需要单独配置在 location 中:

location / {
    proxy_pass http://httpget;
    add_header Content-Type "text/html; charset=utf-8";

    #向上游
    #proxy_http_version 1.1;
    #proxy_set_header Connection "";

    #代理缓存配置
    add_header Nginx-Cache "$upstream_cache_status";
    proxy_cache test_cache;
    proxy_cache_valid 1h;
    }

这个配置表示再次请求到上游服务器的时间,因为刚才没有配置所以每次都会请求到上游。

valid 和 inactive=1d 配置是冲突的,可以修改为一样的(如上)。

配置完再次刷新可以的看到缓存命中了:

响应头里 Nginx-Cache 变成 HIT,状态码 304

此时查看设定的缓存目录:

root@VM-0-12-ubuntu:/etc/nginx/sites-available# ls -alh /var/cache/nginx
total 12K
drwx------  3 www-data root     4.0K Jul 16 19:28 .
drwxr-xr-x 15 root     root     4.0K Jul 16 19:13 ..
drwx------  3 www-data www-data 4.0K Jul 16 19:28 a

我们可以安装一下 tree 工具更直观地查看这个目录:

apt -y install tree

查看:

root@VM-0-12-ubuntu:/etc/nginx/sites-available# tree /var/cache/nginx
/var/cache/nginx
└── a
    └── 59
        └── 2b1ca16e2a67341af5dfbbf8f501459a

第一级目录是 1 字符,第二级是 2 字符。

http 块中 keys_zone=test_cache:100m 的配置对应的是 location 的 proxy_cache test_cache; 也就是在指定 location 下使用缓存,使用哪一个缓存配置的具体参数。

100m 表示在内存中可以使用的大小,在访问磁盘文件的时候需要索引(所有的 key 存在哪里),内存存的就是索引(文件名的哈希值)。如果没有索引会把请求转化为哈希值然后找文件(全盘扫描),这个速度很慢,所以选择把 url 生成的 hash 缓存到内存,提升查找速度。

总之这个大小关乎着查找速度。

max_size 表示最多存入多少缓存。

add_header Nginx-Cache "$upstream_cache_status"; 这个是一个系统的变量,表示当前的缓存是否命中。

假设删除掉上游的静态资源,访问资源页还能正常显示吗?

是可以的。因为使用了本机磁盘的缓存而不对后端发请求。

假设又删了缓存文件,此时访问就是 404(资源不存在)。

至此,基本的配置了解的差不多了,下面深入解释 proxy_cache 机制。

想要手动管理文件,需要搞清楚这些文件是什么:

root@VM-0-12-ubuntu:/etc/nginx/sites-available# tree /var/cache/nginx
/var/cache/nginx
└── a
    └── 59
        └── 2b1ca16e2a67341af5dfbbf8f501459a

打开查看:

root@VM-0-12-ubuntu:/var/cache/nginx# cat /var/cache/nginx/a/59/2b1ca16e2a67341af5dfbbf8f501459a
s͘j!Sjc󿿘jx\¤f 
KEY: http://httpget/
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.12.3
Date: Thu, 16 Jul 2026 11:28:35 GMT
Content-type: text/html
Content-Length: 8
Last-Modified: Sun, 12 Jul 2026 03:12:33 GMT

分压2

上部分是文件信息,下半部分是缓存的内容。

这部分到这里就结束了,跳过了第三方模块的内容。

Nginx 断点续传

断点续传介绍

Nginx 原生支持 proxy_cache_max_range_offset 100m; 限制了缓存上游服务器的最大 range(超过 100MB 的大文件跳过缓存直接透传给客户端,避免超大文件占满缓存目录)。

range 是什么?访问服务器的内容的时候不一定从第 0 字节开始,服务器支持 range(范围)加载、读取文件的使用场景:看视频拖动滚动条,加载到具体的位置,此时有两种方式,第一是全下载下来,浏览器本地缓存访问,第二是边播放边缓冲,此时向服务器发送 range 请求,从开始位置到结束位置重新加载,此时需要用到 range 配置。

nginx 默认开启了 range,tomcat 默认不开启。

如果想关掉 range 的方式直接把 content-type 改为 stream,stream 传输时大小是未知的,自然无法通过 range 的方式获取(比如直播就能用这种方式)。

206 表示只返回了部分内容:

状态码 206 Partial Content 的说明,range 头让服务器只发一部分

proxy_cache 配置和断点续传配置

proxy_set_header Range $http_range; 对断点续传缓存必须传入客户端的请求头,告知上游是发送整个文件还是部分文件。

proxy_cache_max_range_offset 100m; 超过多少不缓存直接传整个文件。

proxy_cache_methods 默认的 head、get 请求会被缓存,post 也可以加入,默认不支持。

proxy_cache_min_uses 默认值为 1,用户请求资源多少次之后才去缓存资源(判断是否是热点资源,高并发系统可以设置为 1000)。

proxy_cache_path 指定缓存的目录之前在 nginx.conf 配置过,以 cache_key 获取 md5 的值。

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=test_cache:100m  inactive=1d max_size=10g;

max_size 最大缓存。

假设想要扩容,但是要用到之前的缓存,不能改变缓存路径,加磁盘怎么合并文件目录呢?之前标识了文件生成目录的规则 levels=1:2 第一级 1 字符,第二级 2 字符,可以在第一级针对具体的字符目录通过软连接链接到另一个物理磁盘(软连接:创建快捷方式,让系统认为目录在 A 位置,实际写入 B 位置,可以链接文件、目录、磁盘)。

也可以使用 TMPFS(不常用了,磁盘可以用 200g 的 SSD,而不是一个 200g 的内存),虚拟一个本机磁盘路径,写入的数据实际在内存(实际可以用来做高速缓存)。

inactive 1d 指定固定的时长清理缓存(注意,上面的踢掉的缓存是否过期与删除缓存是不冲突的)。

use_temp_path 老版本 nginx 缓存文件写入磁盘时先创建临时文件,完成之后再挪走,这个是基于磁盘的缓冲区而非内存,在此配置缓存文件目录,缓存的时候先写入这里,写入完成之后移动到配置的缓存目录(建议关闭)。

proxy_cache_use_stale 在反向代理访问配置的过期的缓存,什么情况可以使用。

proxy_cache_use_stale 可选的值,error、timeout、http_500、http_404 等

proxy_cache_background_update 更新缓存同时操作两步:用过期缓存响应数据,到上游服务器请求数据,默认 off。

proxy_no_cache 和 proxy_cache_bypass 不缓存的资源,直接到上游服务器请求。

proxy_no_cache 后面接的一组变量,cookie_nocache、arg_nocache、http_pragma 等

静态资源去缓存取,专门写一个 location。动态不去缓存写另一个 location。

变量存在,不为空不为 0 则不使用缓存。

proxy_cache_convert_head 把 get(有 body)和 head(只请求头)请求变为一样的。就比如相同的 uri 请求,get 方式可以获取内容,head 方式不行,假设 nginx 缓存的 head 请求,那么用户使用 get 请求就无法获取内容了,所以需要配置:head 和 get 都拉取完整内容缓存。

proxy_cache_lock 更新缓存是否加锁,不加锁可以多线程竞争覆盖,默认 off,加了可能造成响应变慢。

proxy_cache_lock_age 锁的时间,默认 5s。

proxy_cache_key 一个索引,通过索引找文件,默认:

$scheme$proxy_host$request_uri 配置的时候必须唯一。

proxy_cache_revalidate 缓存过期是拉取文件还是发送 If-Modified-Since 和 If-None-Match 验证是否改变(协商缓存),如果没有就不需重新下载资源了。

proxy_cache_valid 缓存文件的过期时间,inactive 仅仅指定了过期时间,这个配置可以更详细地指定过期文件。

比如 200、302 配置为 10s,301 配置为 1h:

proxy_cache_valid 按状态码分别配置过期时间,不设置状态码默认 200、301、302

上述参数全部来自官方文档,用到了可以具体再看,没必要都记。

Nginx 内外缓存和扩展内容介绍

内置缓存

nginx 会在内存建立文件索引缓存,高效访问文件。

假设一个 index.html,nginx 在内存缓存索引,多进程共享缓存时,除了缓存元数据,还会缓存内容,所以往往只会缓存元数据的索引(适合磁盘文件多、文件大的情况)。

多进程共享缓存适合高频的访问,内容不适用太大,一般都是静态资源、接口数据。

外置缓存(应用很多)

不占用 nginx 的内存,内存占满的情况很难扩容了,因为主板很可能不支持,所以可以优化外置机器,让 nginx 访问机器(业务也很成熟比如缓存中间件 Redis)。

那么外置这么大的内存存什么?可以是 DB 的表。

如何同步数据?多机多写同步(变成一个事务)。

应用缓存/多级缓存整体结构

用户、DNS、CDN、Nginx 一路下来,Nginx 上挂的那几种缓存

对上图补充:DNS 有缓存(之前了解了 DNS-bind),CDN 建议缓存不总是变化的数据。

再往右加上 Tomcat,里面有静态缓存、ehcache、guava,还能访问外置缓存

在 tomcat 中,java 内存就有缓存(静态变量不需要管理),内部还有 ehcache、guava,后端服务器还能访问 nginx 的外置缓存。

缓存链条很清晰了:用户(客户端)--DNS--CDN--nginx相关--后端

实际的企业开发中,基本是只有 nginx 相关就够用了。