openresty通过lua实时查询redis动态设置$skip_cache变量,驱动proxy_cache_bypass和proxy_no_cache实现安全可控的缓存绕过;需在access阶段查redis、设超时降级、按路径/用户/环境分级设key并配ttl,避免客户端随意触发。

缓存绕过结合 Redis 状态动态控制 Nginx 缓存开关,本质是把“是否绕过缓存”的决策权从静态配置(如请求头、参数)转移到运行时可变的外部状态。Nginx 本身不支持原生 Redis 查询,必须借助 OpenResty + Lua 实现——这不是 proxy_cache_bypass 的常规用法,而是用 Lua 在请求入口实时查 Redis,再决定是否启用 bypass 逻辑。
核心思路:用 Lua 查 Redis,驱动 proxy_cache_bypass 变量
proxy_cache_bypass 只接受变量,且变量值需为非空/非零才生效。所以不能直接写 proxy_cache_bypass $redis_result($redis_result 是 Lua 运行时生成的,Nginx 配置阶段不可见)。正确做法是:在 access 阶段用 Lua 查询 Redis,根据结果设置一个自定义变量(如 $skip_cache),再让 proxy_cache_bypass 和 proxy_no_cache 共同引用它。
具体实现步骤
以下配置基于 OpenResty,需确保已安装 lua-resty-redis 模块:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
在 http 块声明共享字典用于缓存 Redis 查询结果(可选但推荐)
防止每次请求都连 Redis:
lua_shared_dict redis_bypass_cache 5m; -
在 location 中嵌入 access_by_lua_block
提取请求特征(如 URI、用户 ID、环境标识),构造 Redis key(如bypass:api:/user/1001或bypass:env:staging),查询值:
若返回"1"、"true"或"on",则设置ngx.var.skip_cache = "1";否则设为空或"0" -
在同一个 location 中启用双指令
proxy_cache_bypass $skip_cache;
proxy_no_cache $skip_cache;
注意:必须同时配proxy_cache mycache,且变量名严格一致 -
加超时与降级保障
Lua 中调用 Redis 必须设set_timeout(100)(单位毫秒),超时或失败时默认不绕过(即skip_cache = ""),避免因 Redis 不可用导致全量 bypass、压垮后端
Redis 数据设计建议
不要用单个全局开关(如 bypass:all),而应按维度分级控制,便于灰度和快速收敛:
-
路径粒度:key =
bypass:path:/api/order,value ="1",适用于临时屏蔽某接口缓存 -
用户/角色粒度:key =
bypass:user:admin_123,value ="dev",配合 map 规则映射为布尔值 -
环境+服务组合:key =
bypass:env:prod:service:user-api,value ="true",适配多环境发布验证 - 所有 key 应设 TTL(如 300 秒),避免误写后长期生效;后端发布系统可自动写入/清理
为什么不直接用 proxy_cache_bypass + $arg_xxx?
URL 参数或请求头方式简单,但存在明显短板:
- 无法做权限校验——任何人都能加
?nocache=1,可能暴露调试接口或拖垮后端 - 无法按用户/设备/地域等复杂条件批量控制,只能靠客户端主动携带
- 缺乏审计和生命周期管理——Redis 方式可记录谁在何时启用了哪条规则,支持自动过期
Redis 动态控制不是替代,而是升级:它把 bypass 从“客户端可触发”变成“运维/开发可编排”,更安全、更精准、更可运维。










