在讲解 Nginx 反向代理缓存的具体配置前,理解其内部处理流程至关重要。整个流程可以划分为两个部分:处理客户端请求与处理上游服务器响应。通过流程分析,可以帮助我们更好地理解后续各个缓存指令的具体作用。
第一部分:客户端请求的缓存处理流程
-
检查是否开启 proxy_cache 指令。必须配置 proxy_cache zone_name; 指令,其中 zone_name 为共享内存块名称。若未配置,则直接向上游发送请求,不进行任何缓存操作。
-
检查请求方法是否匹配 proxy_cache_methods 指令规定的方法,默认只缓存 GET 和 HEAD 请求。
-
检查 proxy_cache_convert_head 指令决定是否将 HEAD 请求视为 GET 请求处理。若开启转换,则后续流程按GET请求对待,允许使用缓存。
-
使用 proxy_cache_key 指令定义缓存关键字。默认关键字为 $scheme$proxy_host$request_uri 组成,可自定义变量组合生成关键字。关键字经MD5哈希处理以缩短长度并提高查找效率。
-
检查 proxy_cache_bypass 指令值。若变量值为真(非空且不为“0“),则跳过缓存,直接向上游发送请求。这常用于动态绕过缓存的场景,如带特定参数时不使用缓存。
-
在 proxy_cache 指定的共享内存区域中查找对应关键字的缓存项(使用二叉树查找)。若缓存不存在,则在共享内存中分配新节点,标记该请求将使用缓存并向上游发送请求等待响应。若缓存存在,则更新LRU链表,将当前缓存项移至头部,避免近期被淘汰,同时更新节点访问次数,用于 proxy_cache_min_uses 指令判断。
-
检查缓存响应状态与过期情况。若缓存响应为错误类(如404、500)且已过期,则不使用缓存,直接向上游发送请求;若非错误响应且未过期,则直接向下游返回缓存内容;若非错误响应但已过期,便根据 proxy_cache_background_update 指令判断是否启用后台更新。若启用,则立即用过期缓存响应客户端,同时发起子请求更新缓存;若未启用,则阻塞等待上游新响应后再返回。
-
共享内存节点分配失败处理。若首次分配节点失败,尝试淘汰已过期的缓存条目释放空间,再次尝试分配;若再次分配仍失败,放弃使用缓存,请求不再经过缓存模块处理,直接透传至上游。
图1:Nginx客户端请求缓存处理流程图

第二部分:接收上游响应的缓存处理流程
-
检查 proxy_no_cache 指令。若变量值为真(非空且不为“0“),则不使用缓存。
-
检查 proxy_cache_valid 指令。根据响应状态码设置缓存有效期,若响应未匹配此指令规则,则不更新缓存,直接转发响应。
-
判断响应码。若响应码为 200(成功)或 206(部分内容),则更新缓存条目的 ETag 和 Last-Modified 字段,以便后续条件请求使用。
-
处理影响缓存的响应头部。依次检查可能阻止缓存的头部,如 Set-Cookie 头部、Vary 头部(当未被 proxy_ignore_headers 忽略时)将导致不缓存。可通过 proxy_ignore_headers Set-Cookie; 来忽略 Set-Cookie 头。
-
开始读取并转发上游响应。此过程为多次循环操作,因为响应体可能较长,需分块处理。
-
当全部响应读取完毕后,将临时文件重命名为正式缓存文件,并移入缓存目录。此操作本质上是 rename 系统调用。若临时目录与缓存目录位于不同磁盘设备上,rename 操作会退化为“拷贝 + 删除”,性能开销大。因此,建议将临时目录(proxy_temp_path)与缓存目录(proxy_cache_path)置于同一设备。
-
更新共享内存状态。更新共享内存中维护的缓存索引树(如红黑树),记录新缓存项的键(key)与其对应文件路径的关系,以实现快速查找。
图2:Nginx接收上游响应缓存处理流程图

了解流程后,我们来看看具体的缓存指令,它们为 Nginx 的缓存系统提供了精细化的控制能力。
核心缓存指令详解
1. 定义缓存载体与启用缓存
-
proxy_cache_path:设置缓存的路径和核心参数,缓存文件将以 MD5 值命名。
Syntax: proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [min_free=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
Default: —
Context: http
# 关键参数说明:
path: 缓存文件的存储路径
levels: 指定缓存目录的层级,默认为1:2
use_temp_path: 是否使用临时路径存储缓存文件,默认为 on。
keys_zone: 设置共享内存的名称和大小,用于存储缓存元信息。例如:keys_zone=mycache:10m
inactive: 设置非活跃时间,超过此时间的缓存将被自动清理。例如:inactive=60s
max_size: 设置最大磁盘空间使用量,超过后由 cache_manager 进程按LRU淘汰。例如:max_size=1g
manager_files:单次淘汰循环最多处理文件数,默认100
loader_files:单次加载循环最多处理文件数,默认100
# 示例:
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;
# 生成的文件路径格式类似:/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c
proxy_cache: 指定 proxy_cache_path 指令创建的共享内存区域名称,以启用缓存。
Syntax: proxy_cache zone | off;
Default: proxy_cache off;
Context: http, server, location
2. 定义缓存策略与控制行为
-
proxy_cache_key: 设置缓存的关键字,可使用任意 Nginx 变量组合。
Syntax: proxy_cache_key string;
Default: proxy_cache_key $scheme$proxy_host$request_uri;
Context: http, server, location
# 示例1:包含查询参数
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
# 示例2:包含Cookie值
proxy_cache_key "$host$request_uri$cookie_user";
proxy_cache_methods: 允许缓存的请求方法,默认为 GET 和 HEAD。
Syntax: proxy_cache_methods GET | HEAD | POST ...;
Default: proxy_cache_methods GET HEAD;
Context: http, server, location
proxy_cache_convert_head: 允许将 HEAD 请求转换为 GET 请求进行缓存。若为 off 则 HEAD 请求不会命中 GET 的缓存。
Syntax: proxy_cache_convert_head on | off;
Default: proxy_cache_convert_head on;
Context: http, server, location
-
proxy_cache_valid: 设置不同响应状态码的缓存时间。
Syntax: proxy_cache_valid [code ...] time;
Default: —
Context: http, server, location
# 示例:
proxy_cache_valid 5m; # 对200、301、302等响应码缓存5分钟
proxy_cache_valid 200 302 10m; # 仅对200和302响应码缓存10分钟
proxy_cache_min_uses: 设置缓存项在达到此使用次数后才被认为是有效的。
Syntax: proxy_cache_min_uses number;
Default: proxy_cache_min_uses 1;
Context: http, server, location
-
proxy_no_cache: 设置不缓存的请求条件。当任一变量非空(true)时,不缓存该响应。
Syntax: proxy_no_cache string ...;
Default: —
Context: http, server, location
# 示例:
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
-
proxy_cache_bypass: 设置不使用缓存的请求条件。即使存在有效缓存,满足条件时也向上游请求。
Syntax: proxy_cache_bypass string ...;
Default: —
Context: http, server, location
# 示例:
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_max_range_offset: 设置缓存范围请求的最大偏移量(字节),超出此值将不使用缓存。
Syntax: proxy_cache_max_range_offset number;
Default: —
Context: http, server, location
缓存状态变量
Nginx 的 $upstream_cache_status 变量记录了缓存命中状态,可在日志或响应头中输出,其值含义如下:
- HIT:命中缓存
- MISS: 未命中缓存
- BYPASS: 因
proxy_cache_bypass 生效而未使用缓存
- EXPIRED: 缓存已过期(根据上游头判断)
- STALE: 命中陈旧缓存(因启用陈旧缓存功能)
- UPDATING: 缓存过期且正在后台更新,当前返回旧内容
- REVALIDATED: 经异步验证后确认陈旧内容已更新
实践配置:探究上游响应头对缓存的影响
目标:配置 Nginx 反向代理缓存,并测试上游服务器不同响应头对缓存行为的覆盖或影响。
步骤1:配置上游服务器
创建两个监听不同端口(8010, 8011)的服务来模拟上游服务器,并使用 upstream 模块定义服务器组。
tee backend_server.conf << 'EOF'
# 定义上游服务器组
upstream backend_server {
zone backend_zone 64k;
server 10.20.172.214:8010;
server 10.20.172.214:8011;
keepalive 10;
keepalive_timeout 60s;
}
# 模拟上游服务器 8010
server {
listen 8010;
server_name _;
charset utf-8;
default_type text/plain;
location / {
root /usr/local/nginx/html;
index index.html;
}
location ^~ /api {
return 200 '$time_iso8601 $request_id $server_addr:$server_port $request_uri\n';
}
}
# 模拟上游服务器 8011
server {
listen 8011;
server_name _;
charset utf-8;
default_type text/plain;
location / {
root /usr/local/nginx/html;
index index.html;
}
location ^~ /api {
return 200 '$time_iso8601 $request_id $server_addr:$server_port $request_uri\n';
}
}
EOF
步骤2:配置Nginx反向代理与缓存
定义缓存路径,并在虚拟主机中启用缓存策略。
tee test.conf << 'EOF'
# 定义缓存路径与共享内存区
proxy_cache_path /usr/local/nginx/cache levels=2:2 keys_zone=data01:10m loader_threshold=300 loader_files=200 max_size=128m inactive=1m;
server {
listen 80;
server_name test.weiyigeek.top;
charset utf-8;
default_type text/html;
http2 on;
location / {
proxy_pass http://backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 启用缓存
proxy_cache data01;
proxy_cache_valid 200 1m; # 缓存200响应1分钟
add_header X-Cache-Status $upstream_cache_status; # 输出缓存状态
}
}
EOF
重启Nginx服务后,进行测试。首次请求状态为 MISS,二次请求为 HIT,一分钟后请求为 EXPIRED 并重新获取。
图3:验证基础缓存配置效果

步骤3:测试上游响应头的影响
在上游服务器配置中添加特定响应头,观察其对Nginx缓存行为的覆盖。
图4:X-Accel-Expires头覆盖缓存时间

Cache-Control 头:同样会覆盖Nginx的缓存设置,并可定义更复杂的缓存行为。
# 在上游 location ^~ /api {} 块中添加,替换 return 前的注释
add_header Cache-Control "public, max-age=3, stale-while-revalidate=3";
测试命令:curl http://test.weiyigeek.top/api -i
结果:缓存有效期被设置为3秒,并允许在过期后3秒内使用陈旧缓存。
图5:Cache-Control头定义复杂缓存策略

图6:Vary: 头导致缓存失效

通过以上实践,我们深入理解了Nginx反向代理缓存的工作流程、核心指令的用法,以及上游服务器如何通过响应头来影响甚至控制缓存行为。合理配置这些指令和头信息,是构建高效、可控缓存系统的关键。

|