Nginx变量默认惰性求值且缓存结果,仅首次读取调用get_handler并存入r->variables数组;缓存生效需满足注册无NGX_HTTP_VAR_NOCACHEABLE、未跨阶段、未reload、handler返回NGX_OK且设v->valid=1。

nginx 变量默认不预先计算,只在首次被读取时调用 get_handler 获取值,并把结果存进当前请求的 r->variables 数组(按索引定位),后续读取直接返回缓存值——这是提升复杂配置性能的关键前提。
变量缓存生效的前提条件
缓存不是自动对所有变量启用的。要让 ngx_http_variable_value_t 中的 valid = 1 和 no_cacheable = 0 发挥作用,需满足:
- 变量注册时未设置
NGX_HTTP_VAR_NOCACHEABLE标志 - 当前请求未跨阶段(如从 rewrite 进入 access)触发强制刷新
- 配置未 reload,避免整个
r->variables数组重置 - handler 返回
NGX_OK且显式设置v->valid = 1,否则本次缓存失败,下次仍会重算
手动控制缓存生命周期的实用方式
当业务逻辑需要变量“每次取新值”或“强制更新”,可主动干预缓存状态:
- 注册变量时设
flags |= NGX_HTTP_VAR_NOCACHEABLE,适用于时间戳、随机数、实时请求头等动态值 - 在 handler 内部根据条件跳过赋值(如
v->not_found = 1),下一次读取会重新触发 handler - 调用
ngx_http_clear_variable(r, &var)清除指定变量缓存,适合在 rewrite 阶段中途重置某个自定义变量 - 避免在 set_handler 中修改只读内置变量(如
$host),否则可能因NGX_HTTP_VAR_CHANGEABLE检查失败而报错
在复杂配置中高效读取变量的推荐写法
使用索引访问比字符串查找快一个数量级,尤其在频繁执行的 location 或 if 块中:
- 在模块
preconfiguration阶段用ngx_http_get_variable_index(cf, &name)预先获取变量索引 - 运行时优先调用
ngx_http_get_indexed_variable(r, index),它直接查数组,不走 hash 表 - 若需兼容不可缓存变量,改用
ngx_http_get_flushed_variable(r, index),它会检查no_cacheable并按需重算 - 不要在 handler 中反复调用
ngx_http_get_variable(r, &name, key)做字符串匹配,开销大且易受哈希冲突影响
常见误用导致缓存失效的典型场景
看似合理的配置,可能无意中绕过了缓存机制:
- 在
if块中嵌套使用set $a $b+proxy_pass http://$a:set创建的是可变变量,但proxy_pass脚本引擎会在每次请求中重建执行单元,实际仍走 get_handler - 把
$arg_xxx直接用于 map 的 key:虽然$arg_*是惰性求值,但它本身带NGX_HTTP_VAR_NOCACHEABLE,每次解析都重新提取参数 - 自定义变量 handler 中忘记设置
v->data和v->len,即使v->valid = 1,Nginx 仍视为无效值并重试 - 在 log_format 中大量引用未索引的自定义变量,导致每个日志行都触发一次 hash 查找和 handler 调用



















