直接用 Lua 控制 Nginx 缓存的核心是动态决策缓存行为:通过 lua_shared_dict 实现跨 worker 内存缓存,结合请求参数、用户身份、响应状态等条件,在 rewrite 或 access 阶段介入判断是否缓存、缓存时长及多级协同策略。

直接用 Lua 控制 Nginx 缓存,核心在于绕过传统 proxy_cache 的粗粒度限制,实现按请求参数、用户身份、响应状态等条件动态决定是否缓存、缓存多久、缓存到哪一级。这不是简单开关,而是把缓存逻辑写进请求生命周期里。
用 lua_shared_dict 做跨 worker 共享缓存
这是最常用也最稳妥的本地缓存方式。它在 Nginx 所有 worker 进程间共享,基于内存 LRU 管理,无网络开销。
- 配置需先在 nginx.conf 的 http 块中声明:
lua_shared_dict my_cache 20m; - Lua 中通过
ngx.shared.my_cache:get(key)和set(key, value, exptime)操作 - key 要有业务语义,比如
"api:" .. ngx.var.host .. ":" .. ngx.md5(ngx.var.args),避免冲突 - exptime 设为 0 表示永不过期(慎用),设为负数表示立即失效;实际建议设为 30–300 秒之间,兼顾新鲜度与命中率
按条件跳过或强制缓存
不是所有请求都适合缓存。Lua 可在 rewrite 或 access 阶段就介入判断,提前终止缓存流程。
- 对带特定 cookie(如
user_role=admin)的请求,直接return不走缓存逻辑 - 对 POST/PUT/DELETE 请求,默认不缓存;但若业务允许幂等写操作的响应缓存(如返回成功 ID),可加白名单判断
- 检查
ngx.var.status—— 若后端返回 404、500,通常不写入缓存,或只缓存极短时间(如 5 秒),防止错误放大 - 用
ngx.req.get_headers()["X-No-Cache"] == "1"支持调试头临时绕过缓存
多级缓存协同:本地 + Redis
单靠 nginx 内存缓存容量有限,且重启即失。结合 Redis 可提升容灾性和一致性。
- 典型顺序:先查
lua_shared_dict→ 未命中则查 Redis → 还未命中才回源 - 命中 Redis 后,顺手
set到本地 dict,加速后续相同请求 - 避免 Lua 直连 Redis Cluster:OpenResty 官方 resty.redis 对集群支持弱;推荐走 HTTP 接口调用独立缓存服务(如用 Go/Java 写的 cache-proxy),由它对接 Redis Cluster 并做连接池、重试、熔断
- 写操作时,先更新 MySQL,再主动
DELRedis key 和本地 dict key,而不是依赖过期——更可控
缓存键与内容的精细化构造
缓存效果好不好,一半看策略,一半看 key 和 value 是否真正反映业务维度。
- 区分移动端和桌面端:在 key 中加入
ngx.var.http_user_agent:match("Mobile") and "mobile" or "desktop" - 支持灰度:若请求头含
X-Env: staging,key 加上":staging"后缀,隔离缓存空间 - value 不建议直接存完整 HTML;优先存结构化数据(JSON),渲染交由 Lua 模板或前端完成,便于复用和压缩
- 对大响应体(>100KB),考虑用
ngx.shared.dict存元信息(如版本号、ETag),主体存 Redis 或对象存储,Nginx 只做协调


















