Nginx lua code cache开关

语法和使用场景

语法: lua_code_cache on | off
使用的上下文:http, server, location, location if
作用:lua_code_cache是nginx_lua模块的一条指令。它为 *_by_lua_file(如 set_by_lua_file 和 content_by_lua_file) 这些指令以及Lua模块, 开启或关闭Lua代码缓存.(nginx_lua模块说明:http://wiki.nginx.org/HttpLuaModule#lua_code_cache)

如果关闭,每个ngx_lua处理的请求将运行在一个独立的Lua VM实例里,0.9.3版本后有效. 所以 set_by_lua_file, content_by_lua_file, access_by_lua_file, 等等指令引用的Lua文件将不再缓存到内存, 并且所有Lua模块每次都会从头重新加载. 这样开发者就可以避免改代码然后重启nginx的操作.
但是, 那些直接写在 nginx.conf 里的代码比如由 set_by_lua, content_by_lua, access_by_lua, and rewrite_by_lua 指定的代码不会在你编辑他们时实时更新,因为只有发送HUP信号通知Nginx才会正确重新加载Nginx的config文件。

即使打开了代码缓存, 那些*_by_lua_file指令里由 dofile 或 loadfile 加载的Lua文件也无法被缓存 (除非你自己手动缓存了他们). 通常你可以用 init_by_lua 或 init_by_lua_file 其中一种指令来加载所有这些无法被缓存 的文件,或把这些文件做成真正的Lua模块并用require加载.

生产环境下千万别关闭Lua代码缓存,只能用在开发模式下,因为对性能有十分大的影响(每次IO读取和编译Lua代码消耗很大, 简单的hello world都会慢一个数量级)

常见问题

网上有很多小伙伴们遇到过和我一样的问题:当lua_code_cache开关打开时,当使用content_by_lua 引入外部的lua文件,并且在lua文件中有对应的内容输出,只有第一次运行脚本的时候正常,如果再次运行,浏览器就会提示500 服务器内部错误。或者第一次请求有响应数据,第二次提示响应数据为空。

问题的原因:

类似这种问题的原因常见的错误是你使用的 lua文件的模块滥用 Lua 全局变量来存放其内部状态信息,而不是模块 table 本身。
而在lua_code_cache on 时,全局变量的生命期是每请求的,所以会出现这种情况:
第一个请求调用 require 加载了你用lua文件写的模块,而你的该模块把内部状态保存在了和第一个请求相关联的某些全局变量中。
后续的各次请求调用 require 时直接返回了步骤 1 中已经加载过的lua模块所对应的 table.
但此时后续请求的全局变量都是干净的(和第一个请求无关),于是该lua模块无法得到它需要的内部状态数据,出现访问未初始化变量的错误。

解决方式和建议:

总是使用下面的形式来加载 Lua 模块:

local foo = require "foo"   -- This is correct! 
而不是简单地 
require "foo"    -- This is wrong!! 


在你自己的 Lua 模块中避免使用 Lua 全局变量(对于必需的文件范围的变量,可以使用 local 在最外层作用域定义之)。

你可以使用下面文档中的办法来检查你的 .lua 文件中是否有使用 Lua 全局变量:
http://lua-users.org/wiki/DetectingUndefinedVariables 
可以使用这篇文章中介绍到的基于 luac 命令行工具的静态代码检查方式来检查是否有使用lua全局变量,即 
luac -p -l yourprogram.lua | grep ETGLOBAL 


上述内容是对下面内容的一个总结(如果看明白了,下面可以不用看了)。


lua_code_cache 问题:
从这里拿的:https://groups.google.com/forum/#!topic/openresty/W0dvD5Wm0Bw

4 名作者发布了 6 个帖子
 
 
赵旭海 
12/12/18
我在我的lua脚本中引用了一个外部文件,用于序列化的, 叫做serialize.lua。我把它放到了lua_ package_path指向的目录中。
然后在自己的lua脚本中require "serialize.lua"
并且在程序中可以直接使用serialize( )和unserialize( )直接序列化和解序列化。

但这是在lua_code_cache为off的情况。
如果把lua_code_cache设置为on时, 只有第一次运行脚本的时候正常,如果再次运行, 浏览器就会提示500 服务器内部错误。

生产环境要求lua_code_cache是on的, 请问该怎么办。。 是我引用的方式不对吗。

多谢了,急救!
-- 
Xuhai Zhao(赵旭海)
Tel: 15841155272
Cyber-Physical Systems  Lab
School of Software
Dalian University of Technology

smallfish 
12/12/18
打开一下nginx的错误日志,50x错误日志里有信息的。
--
smallfish  http://chenxiaoyu.org



2012/12/18 赵旭海  <[email protected]>
- 显示引用文字 -
- 显示引用文字 -
-- 
邮件自: 列表“openresty”,专用于技术讨论!
发言: 请发邮件到  [email protected]
退订: 请发邮件至  [email protected]
详情:  http://groups.google.com/group/openresty
官网:  http://openresty.org/
仓库:  https://github.com/agentzh/ngx_openresty
建议: 提问的智慧  http://wiki.woodpecker.org.cn/moin/AskForHelp
教程:  http://agentzh.org/misc/nginx/agentzh-nginx-tutorials-zhcn.html

agentzh 
12/12/22
Hello!

2012/12/18 赵旭海:


> 我在我的lua脚本中引用了一个外部文件,用于序列化的, 叫做serialize.lua。我把它放到了lua_ package_path指向的目录中。
> 然后在自己的lua脚本中require "serialize.lua"
> 并且在程序中可以直接使用serialize( )和unserialize( )直接序列化和解序列化。
>
> 但这是在lua_code_cache为off的情况。
> 如果把lua_code_cache设置为on时, 只有第一次运行脚本的时候正常,如果再次运行, 浏览器就会提示500 服务器内部错误。
>

建议如 smallfish 所言检查你的 nginx 错误日志里的错误信息(同时确保你的 error_log 配置指令没有设置像 alert
或者 crit 这样过高的日志过滤级别)。

一个常见的错误是你使用的 serialize 模块滥用 Lua 全局变量来存放其内部状态信息,而不是模块 table 本身。而在
lua_code_cache on 时,全局变量的生命期是每请求的,所以会出现这种情况:

1. 第一个请求调用 require 加载了你的 serialize 模块,而你的 serialize
模块把内部状态保存在了和第一个请求相关联的某些全局变量中。
2. 后续的各次请求调用 require 时直接返回了步骤 1 中已经加载过的 serialize 模块所对应的 table.
但此时后续请求的全局变量都是干净的(和第一个请求无关),于是 serialize
模块无法得到它需要的内部状态数据,出现访问未初始化变量的错误。

我就曾经见过一二个第三方 Lua C 模块都犯了此错误。

Best regards,
-agentzh

赵旭海 
12/12/22
嗯嗯, 这个序列化模块没有把里面的函数名在前面用局部变量重新定义一遍 ,报错的时候总说某某全局变量找不到。。。

- 显示引用文字 -
- 显示引用文字 -

--
邮件自: 列表“openresty”,专用于技术讨论!
发言: 请发邮件到  [email protected]
退订: 请发邮件至  [email protected]
详情:  http://groups.google.com/group/openresty
官网:  http://openresty.org/
仓库:  https://github.com/agentzh/ngx_openresty
建议: 提问的智慧  http://wiki.woodpecker.org.cn/moin/AskForHelp
教程:  http://agentzh.org/misc/nginx/agentzh-nginx-tutorials-zhcn.html



-- 
Xuhai Zhao(赵旭海)
Tel: 15841155272
Cyber-Physical Systems  Lab
School of Software
Dalian University of Technology
范洪毅 
13/7/25
我在开发中也遇到类似问题,我在require脚本中 的function 都加加上local 还是没有解决问题?请问具体的解决办法是?

在 2012年12月18日星期二UTC+8下午5时10分39秒, 赵旭海写道:
- 显示引用文字 -
agentzh 
13/7/26
Re: [openresty] Re: lua_code_cache 问题
Hello! 

2013/7/25 范洪毅: 
> 我在开发中也遇到类似问题,我在require脚本中 的function 都加加上local 还是没有解决问题?请问具体的解决办法是? 


请提供一个最小化的能复现问题的代码示例(及相关配置)。 由于你没有提供任何具体信息, 所以我无从帮你判断你的代码中的具体问题所在 :) 

下面是两个针对此类问题的一般性的建议: 

1. 总是使用下面的形式来加载 Lua 模块: 

    local foo = require "foo"   -- This is correct! 

而不是简单地 

    require "foo"    -- This is wrong!! 

2. 在你自己的 Lua 模块中避免使用 Lua 全局变量(对于必需的文件范围的变量,可以使用 local 
在最外层作用域定义之)。你可以使用下面文档中的办法来检查你的 .lua 文件中是否有使用 Lua 全局变量: 

     http://lua-users.org/wiki/DetectingUndefinedVariables 

我自己一般喜欢使用这篇文档中介绍的基于 luac 命令行工具的静态代码检查方式,即 

    luac -p -l myprogram.lua | grep ETGLOBAL 

Regards, 
-agentzh 




你可能感兴趣的:(Nginx lua code cache开关)