Nginx lua

Nginx lua

最先将 Nginx,Lua 组合到一起的是 OpenResty,它有一个 ngx_lua 模块,将 Lua 嵌入到了 Nginx 里面;随后Tengine 也包含了 ngx_lua 模块。

至于二者的区别:OpenResty 是 Nginx 的 Bundle;而 Tengine 则是 Nginx 的 Fork。值得一提的是,OpenResty 和 Tengine 均是国人自己创建的项目。

Lua简介

Lua 是一个简洁、轻量、可扩展的脚本语言,也是号称性能最高的脚本语言,用在很多需要性能的地方,比如:游戏脚本,nginx,wireshark 的脚本,当你把他的源码下下来编译后,你会发现解释器居然不到 200k,非常变态。很多应用程序使用 Lua 作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。

Lua 原生支持的数据类型非常之少,它只提供了 nil、数字(缺省是双精度浮点数,可配置)、布尔量、字符串、表、子程序、协程(coroutine)以及用户自定义数据这 8 种。但是其处理表和字符串的效率非常之高,加上元表的支持,开发者可以高效的模拟出需要的复杂数据类型(比如集合、数组等)。Lua 是一个动态弱类型语言,支持增量式垃圾收集策略。有内建的,与操作系统无关的协作式多线程(coroutine)支持。它还可以用于嵌入式硬件,不仅可以嵌入其他编程语言,而且可以嵌入微处理器中。

ngx_lua运行指令

ngx_lua 属于 nginx 的一部分,相应的处理阶段可以做插入式处理,即可插拔式架构,不过 ngx_lua 并不是所有阶段都会运行的;另外指令可以在 http、server、server if、location、location if 几个范围进行配置:

指令 所处处理阶段 使用范围 解释
init_by_lua init_by_lua_file loading-config http nginx Master进程加载配置时执行; 通常用于初始化全局配置/预加载Lua模块
init_worker_by_lua init_worker_by_lua_file starting-worker http 每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua之后调用; 通常用于定时拉取配置/数据,或者后端服务的健康检查
set_by_lua set_by_lua_file rewrite server,server if,location,location if 设置nginx变量,可以实现复杂的赋值逻辑;此处是阻塞的,Lua代码要做到非常快;
rewrite_by_lua rewrite_by_lua_file rewrite tail http,server,location,location if rrewrite阶段处理,可以实现复杂的转发/重定向逻辑;
access_by_lua access_by_lua_file access tail http,server,location,location if 请求访问阶段处理,用于访问控制
content_by_lua content_by_lua_file content location,location if 内容处理器,接收请求处理并输出响应
header_filter_by_lua header_filter_by_lua_file output-header-filter http,server,location,location if 设置header和cookie
body_filter_by_lua body_filter_by_lua_file output-body-filter http,server,location,location if 对响应数据进行过滤,比如截断、替换。
log_by_lua log_by_lua_file log http,server,location,location if log阶段处理,比如记录访问量/统计平均响应时间

安装tengine以及Lua扩展

先安装 Nginx 需要的一些类库:

yum install gcc yum install gcc-c++

注:此步骤只是在你的系统没有安装 gcc/gcc-c++ 的情况下才需要自行编译安装。

编译安装库 LuaJit-2.0.3:

./configure --prefix=/usr/local/luajit make PREFIX=/usr/local/luajit make install PREFIX=/usr/local/luajit

在 /etc/profile 文件中增加环境变量,并执行 source /etc/profile 使之生效(非必须):

export LUAJIT_LIB=/usr/install/luajit/lib export LUAJIT_INC=/usr/install/luajit/include/luajit-2.0

注:此步骤只是在你的系统没有安装 LuaJIT 的情况下才需要自行编译安装。

下载模块依赖 pcre-8.34、zlib-1.2.8、ngx_devel_kit 和 lua-nginx-module,最后编译 Nginx。

Nginx配置Lua案例

worker_processes 2; #error_log /var/log/nginx/error.log; pid /var/run/nginx.pid; events { worker_connections 20; } http { server { listen 80; set $idTest "idTest_11111111111" ; log_format tracklog '$idTest $msec $remote_addr - $remote_user [$time_local] $request ' '"$status" $body_bytes_sent --"$ref1"-- ' '"$http_user_agent"'; log_format LogFormatv1 '$idTest@$msec@$remote_addr@-@$remote_user@[$time_local]@$request@' '"$status"@$body_bytes_sent@"$http_referer"@' '"$http_user_agent"'; access_log on; location ~ /lua/(.*) { default_type "text/html"; set $ref1 "Hello,Nginx & Lua !"; #设置nginx变量 set $a $1; set $b $host; content_by_lua ' --nginx变量 local var = ngx.var ngx.say("ngx.var.a : ", var.a, "<br/>") ngx.say("ngx.var.b : ", var.b, "<br/>") ngx.say("ngx.var[2] : ", var[2], "<br/>") ngx.var.b = 2; ngx.say("<br/>") --请求头 ngx.say(ngx.var.httpRef, "<br/>") local headers = ngx.req.get_headers() for k,v in pairs(headers) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ","), "<br/>") else ngx.say(k, " : ", v, "<br/>") end end ngx.say("------------headers end-----------", "<br/><br/><br/>") --get请求uri参数 ngx.say("uri args begin", "<br/>") local uri_args = ngx.req.get_uri_args() for k, v in pairs(uri_args) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ", "), "<br/>") else ngx.say(k, ": ", v, "<br/>") end end ngx.say("uri args end", "<br/>") ngx.say("a: ",ngx.var.arg_a, "<br/>") ngx.say("b: ",ngx.var.arg_b, "<br/>") --未经解码的请求 uri local request_uri = headers["Host"] .. "/" .. ngx.var.request_uri; ngx.say("request_uri : ", request_uri, "<br/>"); --解码后的 uri local decode_request_uri = headers["Host"] .. "/" .. ngx.unescape_uri(ngx.var.request_uri); ngx.var.ref1 = decode_request_uri; ngx.say("decode request_uri : ", decode_request_uri, "<br/>"); --MD5 ngx.say("ngx.md5 : ", ngx.md5("123"), "<br/>") --http time ngx.say("ngx.http_time : ", ngx.http_time(ngx.time()), "<br/>") --ngx.var.http_referer = "*********************" '; access_log /var/log/nginx/ooxx.com.access.log tracklog; } } }

Nginx lua总结

最先将 Nginx,Lua 组合到一起的是 OpenResty,它有一个 ngx_lua 模块,将 Lua 嵌入到了 Nginx 里面;随后Tengine 也包含了 ngx_lua 模块。