Nginx 本身不支持跨节点缓存同步,需借助 OpenResty + lua-resty-redis 将其作为缓存客户端接入 Redis,由 Redis 统一管理数据、生命周期与更新逻辑,实现多实例间强一致性;键需标准化哈希构造,读写加分布式锁防击穿,失效依赖业务主动触发而非被动 TTL。

Nginx 本身不支持跨节点缓存同步,要实现分布式环境下的缓存一致性,不能依赖 Nginx 的 proxy_cache,而应让 Nginx 作为“缓存客户端”接入 Redis,由 Redis 统一管理缓存数据、生命周期和更新逻辑。这种方式把缓存决策权从 Nginx 移到 Redis,真正达成多实例间的数据一致。
用 OpenResty + lua-resty-redis 构建统一缓存层
原生 Nginx 不具备 Redis 访问能力,需借助 OpenResty 及其 Lua 模块:
- 安装 OpenResty,并确保已加载
lua-resty-redis模块 - 在
nginx.conf的http块中初始化 Redis 连接池:
lua_shared_dict redis_cluster 10m;
lua_socket_connect_timeout 500ms;
lua_socket_send_timeout 500ms;
lua_socket_read_timeout 500ms; - 在
location中用 Lua 脚本完成“查缓存 → 未命中则回源 → 写缓存”闭环,缓存键统一构造为:
local key = ngx.md5(ngx.var.host .. ngx.var.uri .. ngx.var.args)
缓存写入与失效必须由业务系统驱动
Redis 缓存的一致性不靠 Nginx 自动感知,而靠后端服务在数据变更时主动通知:
- 数据库更新成功后,服务端调用 Redis 的
DEL或SET指令清理/刷新对应 key(如DEL user:123) - 避免仅靠 TTL 被动过期——对强一致性场景,TTL 应设长(如 24h),靠主动失效兜底
- 若使用消息队列(如 Kafka/RocketMQ),可将缓存失效指令发往 Topic,由消费者广播至所有 Nginx 节点执行本地 Lua 清理(需暴露内部 purge 接口)
关键细节:键设计与并发安全
缓存键必须稳定、可复现,且规避并发写冲突:
- 禁止用
$time_iso8601、$remote_addr等动态变量参与 key 构造 - 对含查询参数的请求,先标准化参数顺序(如按字典序重排
a=1&b=2→a=1&b=2),再哈希 - 读写操作加 Redis 分布式锁(
SET key lock_value NX PX 5000),防止缓存击穿时多个请求同时回源重建 - 对高频热点 key(如首页 HTML),可在 Redis 层启用
GETEX或设置永不过期 + 定期异步刷新,避免雪崩
为什么不推荐 Nginx proxy_cache + 外部 purge?
该方案看似简单,但在分布式下存在明显短板:
- 每个 Nginx 节点缓存独立,purge 需逐台调用,网络失败或节点遗漏即导致不一致
- 无法保证 purge 与数据库更新的时序——可能先删缓存、后写库,中间窗口读到空值
- 无法处理“先读后写”类并发场景(如库存扣减),缺乏原子性保障
- Redis 方案天然支持 CAS、Lua 原子脚本、发布订阅等机制,扩展性与可控性更强


















