Nginx变量默认惰性求值并缓存一次,仅在配置重载、进入新阶段(注册为NOCACHEABLE)、显式清除或handler失败时失效;注册时通过flags控制缓存行为,默认可跨阶段复用,NOCACHEABLE则每次重算。

在 Nginx 模块开发中,变量($xxx)的读取性能直接影响请求处理效率。Nginx 并非每次访问变量都重新计算,而是通过一套轻量、按需触发的缓存机制来避免重复开销。理解这套机制,是写出高性能模块的关键一步。
变量缓存的核心:按需计算 + 标记失效
Nginx 变量默认是“惰性求值”的——只有在配置解析阶段或运行时首次被引用时,才会调用对应变量的 get_handler 回调函数计算值,并将结果缓存在当前请求的 ngx_http_request_t->variables 数组中(以索引为键)。后续对该变量的读取直接返回缓存值,不重复调用 handler。
但缓存不是永久有效的。以下情况会自动标记变量为“过期”,下次读取时强制重算:
- 变量所属的配置块发生重载(如 reload 配置)
- 请求进入新的处理阶段(如从
rewrite进入access),且变量注册时设置了NGX_HTTP_VAR_NOCACHEABLE标志 - 模块显式调用
ngx_http_clear_variable(r, &var)清除指定变量缓存 - 变量 handler 自身返回
NGX_ERROR或未设置v->valid = 1,导致本次缓存失败,下次仍会重试
如何控制变量是否缓存?关键看注册方式
注册变量时,通过 flags 字段决定缓存行为:
-
默认行为(推荐):不设任何 flag → 值缓存一次,跨阶段复用,适合内容稳定、依赖请求上下文但不随阶段变化的变量(如
$request_uri) -
NGX_HTTP_VAR_NOCACHEABLE→ 每次读取都调用 handler,适合值可能随阶段动态变化的变量(如某些鉴权状态、临时生成的 token) -
NGX_HTTP_VAR_NOHASH→ 禁用哈希查找优化,仅用于调试或极特殊场景,不影响缓存逻辑 -
组合使用:例如
NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_PREFIX表示不可缓存且支持前缀匹配
手动清除缓存的典型场景
当模块内部状态变更影响变量语义时,需主动清除缓存,避免旧值被误用。常见例子:
- 在
rewrite阶段修改了 URI,而自定义变量依赖原始 URI → 应在改写后调用ngx_http_clear_variable(r, &my_uri_var) - 模块实现多级 fallback 逻辑,在子请求返回后更新主请求变量 → 必须清除再读取,确保拿到最新值
- 变量值依赖 upstream 响应头,而该响应头在
post_action中才获取 → 注册时设NOCACHEABLE,或在获取后清除并触发重算
调试变量缓存状态的小技巧
开发中可通过以下方式验证缓存是否生效:
- 在
get_handler开头加ngx_log_debug日志,观察同一请求中是否只打印一次 - 使用
curl -v多次请求同一 URL,配合error_log debug;查看 handler 调用频次 - 检查变量结构体中的
v->valid、v->no_cacheable字段值,确认当前缓存状态 - 注意:调试日志本身有开销,上线前务必关闭
变量缓存不是黑盒,它由注册标志、请求生命周期和显式清除三者共同控制。合理利用默认缓存,谨慎添加 NOCACHEABLE,并在状态变更点主动清理,就能在保证语义正确的前提下,把变量读取开销降到最低。

















