据说lua的效率高,公司要求,路过学习下。哎
安装
需要最新版的Nginx,LuaJIT,ngx_devel_kit,ngx_lua等安装文件。
安装Lua或者LuaJIT都是可以的,但是出于效率的考虑,推荐安装LuaJIT。
shell> wget http://luajit.org/download/LuaJIT-<VERSION>.tar.gz
shell> tar zxvf LuaJIT-<VERSION>.tar.gz
shell> cd LuaJIT-<VERSION>
shell> make
shell> make install
因为安装在缺省路径,所以LuaJIT对应的lib,include均在/usr/local目录里。
shell> export LUAJIT_LIB=/usr/local/lib
shell> export LUAJIT_INC=/usr/local/include/luajit-<VERSION>
下面就可以编译Nginx了:
shell> wget http://nginx.org/download/nginx-<VERSION>.tar.gz
shell> tar zxvf nginx-<VERSION>.tar.gz
shell> cd nginx-<VERSION>
shell> ./configure
--add-module=/path/to/ngx_lua \
--add-module=/path/to/ngx_devel_kit
shell> make
shell> make install
试着启动一下Nginx看看,如果你运气不好的话,可能会遇到如下错误:
cannot open shared object file: No such file or directory
这是神马情况?可以用ldd命令来看看:
shell> ldd /path/to/nginx
libluajit-<VERSION>.so => not found
此类问题通常使用ldconfig命令就能解决:
shell> echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf
shell> ldconfig
再试着启动Nginx看看,应该就OK了。
应用
我们先用一个简单的程序来暖暖场:把下面的代码加入到Nginx的配置文件nginx.conf,并重启Nginx,然后浏览,就能看到效果了。
location /lua {
set $test "hello, world.";
content_by_lua '
ngx.header.content_type = "text/plain";
ngx.say(ngx.var.test);
';
}
在深入学习ngx_lua之前,建议大家仔细阅读一遍春哥写的Nginx教程。
这里我就说关键的:Nginx配置文件所使用的语言本质上是『声明性的』,而非『过程性的』。Nginx处理请求的时候,指令的执行并不是由定义指令时的物理顺序来决定的,而是取决于指令所属的阶段,Nginx常用的阶段按先后顺序有:rewrite阶段,access阶段,content阶段等等。演示代码中的set指令属于rewrite阶段,content_by_lua指令属于content阶段,如果试着把两条指令的顺序交换一下,会发现程序依然能够正常运行。
下面我们尝试结合Redis写个更实战一点的例子。
首先,我们需要创建一个Redis配置文件config.json,内容如下:
{
"host": "<HOST>",
"port": "<PORT>"
}
然后,我们创建一个解析配置文件的脚本init.lua,其中用到了Lua CJSON模块:
local cjson = require "cjson";
local config = ngx.shared.config;
local file = io.open("config.json", "r");
local content = cjson.decode(file:read("*all"));
file:close();
for name, value in pairs(content) do
config:set(name, value);
end
说明:代码里用到了共享内存,这样就不必每次请求都解析一遍配置文件了。
接着,我们创建一个渲染内容的脚本content.lua,用到了Resty Redis模块:
ngx.header.content_type = "text/plain";
local redis = require "resty.redis";
local config = ngx.shared.config;
local instance = redis:new();
local host = config:get("host");
local port = config:get("port");
local ok, err = instance:connect(host, port);
if not ok then
ngx.log(ngx.ERR, err);
ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE);
end
instance:set("name", "laowang");
local name = instance:get("name")
instance:close();
ngx.say("name: ", name);
说明:建议把Resty Redis模块放到vendor目录下,稍后在Nginx中统一设置。
最后,我们需要在Nginx配置文件里设置一下:
lua_shared_dict config 1m;
lua_package_path "/path/to/vendor/?.lua;;";
init_by_lua_file /path/to/init.lua;
server {
lua_code_cache off;
location /lua {
content_by_lua_file /path/to/content.lua;
}
...
}
说明:为了方便调试,我关闭了lua_code_cache,如果是生产环境,应该开启它。
另外,安装CJSON的时候,需要注意Makefile文件里头文件的路径,缺省是:
PREFIX = /usr/local
LUA_INCLUDE_DIR = $(PREFIX)/include
如果安装的是LuaJIT的话,最好把头文件拷贝到相应目录:
cp /usr/local/include/luajit-<VERSION>/* /usr/local/include/