第4章:反向代理与网关缓存层
反向代理与网关缓存层位于用户请求进入应用集群的第一道“咽喉”,负责终止客户端连接、TLS卸载、SSL终结,并在L7层缓存可缓存的响应。该层既是流量分发枢纽,也是缓存命中率提升的关键阵地。
4.1 系统边界与分层位置
在整体多级缓存架构中,第1层浏览器缓存(私有/协商缓存)之后,第2层即反向代理与网关缓存层。该层直接面对公网或CDN回源流量,通常与CDN回源节点、微服务网关、API网关共同构成边界。
- 上游:CDN(第0层) 或 浏览器(第1层) 回源;下游:App 服务器集群(第3层本地堆内缓存或分布式缓存)。
- 数据流:请求到达 → DNS/负载均衡器 → 反向代理/网关 → 判断缓存存在 → 返回或转发至下游。
- 控制流:缓存淘汰控制(LRU/TTL)、缓存失效通知(PURGE/BAN)、运维命令(健康检查/限流)。
- 信任链路:反向代理缓存层对客户端证书、JWT等不做深度校验(信任下放给应用层),仅验证必需的安全头部与HTTPS。
4.2 组件职责与核心能力
| 组件 | 角色 | 缓存方式 | 典型性能指标 |
|---|---|---|---|
| Nginx (ngx_cache_purge) | 静态资源 + API 缓存代理 | 文件系统缓存(proxy_cache) | QPS ~ 50k+(单核) |
| OpenResty (LuaJIT) | 自定义缓存策略(热点隔离、内存分级) | shared dict + lua-resty-lrucache | QPS ~ 100k+(Lua非阻塞) |
| Varnish Cache | 专用缓存加速,复杂 VCL 策略 | 内存+文件对象存储 (malloc/stevedore) | QPS ~ 200k+(多核) |
| 网关本地缓存 (Kong/Gateway) | 插件级缓存(如 kongo-cache) | 进程内 LRU Map | QPS ~ 30k~80k(依赖插件) |
4.3 核心数据流与缓存命中流程
以 Nginx 代理缓存为例,请求在反向代理层经历以下步骤:
- 客户端请求 → Nginx 接收,根据
proxy_cache_key计算缓存键。 - 检查对应文件缓存块是否有效(状态 200/301/302,未过期且未因 PURGE 失效)。
- 命中则直接返回缓存响应(
HIT);未命中则转发至后端,缓存新响应(MISS)。 - 控制流:管理员 / 运维系统可通过 HTTP PURGE 方法主动删除缓存,热更新策略。
典型缓存配置片段(Nginx)
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10g
max_size=50g inactive=60m use_temp_path=off;
server {
listen 80;
location /api/ {
proxy_cache mycache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500;
proxy_pass http://backend_cluster;
add_header X-Cache-Status $upstream_cache_status;
}
}
$upstream_cache_status 返回 HIT / MISS / EXPIRED / UPDATING / STALE,便于监控缓存效率。
4.4 选型权衡:Nginx vs OpenResty vs Varnish vs 网关缓存
| 对比维度 | Nginx (ngx_cache) | OpenResty (Lua) | Varnish | 网关本地缓存 |
|---|---|---|---|---|
| 缓存存储 | 磁盘文件(可扩展ssd) | 内存共享字典+SSD | 内存为主 + 对象存储 | 进程内存 |
| 自定义策略 | 弱(靠配置块) | 强(Lua热脚本) | 中强(VCL编程) | 插件约束 |
| 缓存淘汰 | LRU + 过期时间+空间 | LRU + 过期+手动废弃 | LRU + TTL + obj. grace | 固定LRU |
| 集群支持 | 无内置,需做外部一致hash | 无内置,可借助redis/consul | Varnish Cache (加上shard director) | 无(每网关独立) |
| 运维成熟度 | 极高(广泛使用) | 中高(OpenResty社区) | 高(历史悠久) | 中(网关团队维护) |
| 性能(单机QPS) | 50k~80k | 80k~150k | 150k~300k+ | 30k~80k |
选型建议:如果仅做简单静态资源/通用API缓存,Nginx 自带 proxy_cache 已足够。若需要自定义热点隔离、动态缓存过期策略(如按用户ID分桶缓存),选 OpenResty 或 Varnish。如果已部署 API 网关(如Kong),可先启用插件缓存,遇到性能瓶颈再独立部署 Varnish 前置。
4.5 风险点与避坑指南
- 缓存污染:不当的缓存键未包含必要的请求头(如 Accept-Encoding/Auth),导致返回错误内容。解决:精确配置
proxy_cache_key与 use_stale 策略。 - 缓存雪崩:大量缓存同时过期导致瞬时回源激增。需设置随机过期时间(
proxy_cache_valid 200 5m+random(1m))或启用 stale-while-revalidate。 - 缓存穿透:请求不存在资源(如404)可能被缓存,导致后续请求全部回源。应限制
proxy_cache_valid 404 1m或对不存在 key 做布隆过滤器。 - 缓存一致性:后端更新资源后,反向代理层未及时失效。需通过 PURGE 接口或消息队列通知变更。
- 内存/磁盘爆炸:文件系统缓存如 max_size 设置过小,导致高频淘汰。需结合业务 QPS 估算缓存容量,并设置监控告警。
4.6 落地步骤
- 确定缓存场景:识别可缓存请求(GET/HEAD 无副作用,状态码 200/301/302/304);识别不可缓存场景(POST/PUT/DELETE,带Cookie且需鉴权的API)。
- 选择组件并部署:生产推荐 OpenResty 或 Varnish 负载均衡器前置;Nginx 作为反向代理层时可同时做 upstream 负载。
- 配置缓存键与过期规则:设计 key 模板(如 host + uri + args + 部分请求头);按资源特性设置不同 TTL。
- 集成缓存失效接口:部署 PURGE/BAN 端点;对于 Varnish 可使用 vcl_recv 的 ban() 函数;OpenResty 可通过 /purge 路径调用
ngx.shared.MY_DICT:delete(key)。 - 监控与渐进上线:先灰度 10% 流量,观察 $upstream_cache_status 命中率(目标 > 85%);调整 max_size、inactive 参数;设置 Grafana 看板。
- 压力测试与限流:使用 wrk/ab 模拟峰值 QPS,确保缓存层 CPU 不超过 50%;配置 limit_req / limit_conn 防止突发打穿。
4.7 验收标准
- 同一可缓存请求重复10次,至少8次返回
X-Cache-Status: HIT。 - 手动发送 PURGE 后,下次请求为 MISS 且后端正确响应。
- 缓存层单点故障(kill 进程)影响时间 ≤ 30s(自动拉起 + 预热)。
- 缓存命中尖峰(如秒杀)时后端 QPS 波动 ≤ 10% 基线。
- 缓存一致性:后端数据变更后,最长过期时间+ grace 时段内全量节点均返回新数据。
4.8 性能参数参考(实测数据)
| 场景 | Nginx (单核) | OpenResty (4核) | Varnish (4核) | 网关本地缓存 |
|---|---|---|---|---|
| 静态小文件 (1KB) | 45,000 req/s | 120,000 req/s | 280,000 req/s | 60,000 req/s |
| 动态API (2KB响应) | 18,000 req/s | 45,000 req/s | 95,000 req/s | 25,000 req/s |
| 缓存命中率85% | 后端QPS降90% | 后端QPS降95% | 后端QPS降96% | 后端QPS降80% |
| 单机硬件 | 2C4G | 4C8G | 4C8G | 2C4G |
重要风险:实测数据高度依赖硬件、网卡、内核参数及业务逻辑复杂度。建议在自身环境进行基准压测,不要照搬其他团队的数字。
4.9 总结
反向代理与网关缓存层是多级缓存架构中性能提升最大、成本最低的环节之一。通过合理配置 Nginx/OpenResty/Varnish 的缓存策略,可卸载后端80%~95%的请求压力。但必须配套完善的缓存失效机制(PURGE / BAN / 消息通知),并预防缓存雪崩、穿透、污染等陷阱。下一层(第5章)将深入探讨集中式缓存层(Redis/Memcached)的设计。