Lua 是一个简洁、轻量、可扩展的脚本语言,也是号称性能最高的脚本语言,用在很多需要性能的地方,比如:游戏脚本,nginx,wireshark的脚本。很多应用程序使用Lua作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。
Lua原生支持的数据类型非常之少,它只提供了nil、数字(缺省是双精度浮点数,可配置)、布尔量、字符串、表、子程序、协程(coroutine)以及用户自定义数据这8种。但是其处理表和字符串的效率非常之高,加上元表的支持,开发者可以高效的模拟出需要的复杂数据类型(比如集合、数组等)。Lua是一个动态弱类型语言,支持增量式垃圾收集策略。有内建的,与操作系统无关的协作式多线程(coroutine)支持。它还可以用于嵌入式硬件,不仅可以嵌入其他编程语言,而且可以嵌入微处理器中。
Nginx采用模块化的架构,官方版本的Nginx中大部分功能都是通过模块方式提供的,比如Http模块、Mail模块等。通过开发模块扩展Nginx,可以将Nginx打造成一个全能的应用服务器,这样可以将一些功能在前端Nginx反向代理层解决,比如登录校验、js合并、甚至数据库访问等等。
但是,Nginx模块需要用C开发,而且必须符合一系列复杂的规则,最重要的用C开发模块必须要熟悉Nginx的源代码,使得开发者对其望而生畏。
Nginx_Lua_Module
是一个Nginx第三方模块,通过将Lua解释器集成进Nginx的配置中,支持引用Lua脚本文件/代码段实现业务逻辑,从而极大增强了Nginx的能力。由于lua的紧凑、快速以及内建协程,所以在保证高并发服务能力的同时极大地降低了业务逻辑实现成本。
Nginx+Lua是一个非常好的组合,它允许使用一个高性能的脚本语言扩展Nginx。Nginx有很多方法是自带的,但是使用Lua没有限制的。
本文将介绍ngx_lua
的安装与配置过程。
0.1. 下载及安装Lua
进入Lua项目官网下载中心: http://luajit.org/download.html ,选择即将安装的版本下载到自定义路径中:
0.1.1. 下载Lua主程序压缩包
输入如下命令,下载对应的包文件:
wget -c http://luajit.org/download/LuaJIT-2.0.5.tar.gz
0.1.2. 解压及安装
包文件下载完成后,解压压缩包:
tar xzvf LuaJIT-2.0.5.tar.gz
解压完成后,进入安装包主目录,执行make指令安装:
cd <安装包目录>
make install PREFIX=<即将安装Lua主程序的路径>
如:
cd LuaJIT-2.0.5
make install PREFIX=/usr/local/LuaJIT-2.0.5
0.1.3. 配置Lua环境变量
以 vim /etc/profile
命令编辑 /etc/profile 文件,添加 LUAJIT_LIB
和 LUAJIT_INC
变量:
export LUAJIT_LIB=/usr/local/LuaJIT-2.0.5/lib
export LUAJIT_INC=/usr/local/LuaJIT-2.0.5/include/luajit-2.0
输入 source /etc/profile
命令使环境变量立即生效。
0.2. 获取 ngx_devel_kit 部件安装包
输入 wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
下载ngx_devel_kit 安装文件压缩包。
下载完成后,输入 tar -xzvf v0.3.0.tar.gz
解压。
0.3. 获取 lua-nginx-module 部件安装包
输入 wget https://github.com/openresty/lua-nginx-module/archive/v0.10.8.tar.gz
下载lua-nginx-module 部件压缩包。
下载完成后,输入 tar -xzvf v0.10.8.tar.gz
解压。
0.4. 配置Nginx-configure
假设Nginx已安装完成,现在需要重新集成 ngx_devel_kit
和 lua-nginx-module
两个模块。
进入Nginx程序路径,输入 ./sbin/nginx -V
,查看并记录Nginx的configure参数:
在当前的配置参数之后追加 add-module
信息,将ngx_devel_kit
和 lua-nginx-module
集成入配置参数,如:
./configure --prefix=/usr/local/nginx --add-module=/usr/local/src/ngx_devel_kit-0.3.0 --add-module=/usr/local/src/lua-nginx-module-0.10.8
接下来进入Nginx安装文件路径,以上述configure参数重新make:
cd /usr/local/src/nginx-1.11.3/
make clean
./configure --prefix=/usr/local/nginx --add-module=/usr/local/src/ngx_devel_kit-0.3.0 --add-module=/usr/local/src/lua-nginx-module-0.10.8
make -j2
make install
此时Nginx已成功集成lua-nginx-module, nginx.conf
配置文件中可插入lua代码片段,进行更多性能配置。
make之后启动nginx的过程中可能会报错:
libluajit-5.1.so.2: cannot open shared object file: No such file or directory
这是因为编译时没有生成动态链接库,只能手动链接,具体步骤如下:
- 以
vim /etc/ld.so.conf.d/libc.conf
命令,编辑libc.conf文件,追加Lua编译安装后的lib路径,如:/usr/local/LuaJIT-2.0.5/lib
。- 运行
ldconfig
命令。- 再次启动Nginx即可。
0.5. 在Nginx-conf文件中添加Lua脚本,辅助location配置
例:
0.5.1. nginx.conf(片段)
upstream www.vspnoa.tomcat_colony {
server localhost:8091;
server localhost:8092;
server localhost:8093;
server localhost:8090;
fair;
}
upstream www.vspnoa.tomcat_approve_process_colony {
server localhost:8096;
server localhost:8097;
fair;
}
upstream www.vspnoa.tomcat_finance_process_colony {
server localhost:8098;
server localhost:8099;
fair;
}
upstream www.vspnoa.tomcat_colony_main_server {
server localhost:8090;
}
server {
listen 80;
server_name localhost;
location /VSPNOA/ {
error_log logs/oa_request.log error;
lua_code_cache on;
#(配置请求体缓存区大小, 不配的话默认值:1k )
client_body_buffer_size 128k;
#设置客户端请求体最大值
client_max_body_size 50m;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度;
#上游服务器通信超时时间的配置factcgi_connect/read/send_timeout
#Nginx 504 Gateway Time-out设置优化,避免频繁发生504错误
fastcgi_connect_timeout 1200;
fastcgi_send_timeout 600;
fastcgi_read_timeout 600;
fastcgi_buffer_size 256k;
fastcgi_buffers 16 256k;
fastcgi_busy_buffers_size 512k;
fastcgi_temp_file_write_size 512k;
fastcgi_intercept_errors on;
if ($request_uri ~* ^/VSPNOA/$) {#只有域名,后面不跟任何东西
proxy_pass http://www.vspnoa.tomcat_colony_main_server;
break;
}
if ($request_uri ~* ^/VSPNOA/(js|sources|img|images|font|css|Charts)/(.*)$) {
#OA系统脚本文件储存路径
root /;
rewrite ^/VSPNOA/(.*)$ /var/PROJ_FILE_WAREHOUSE/oa_prod_scripts_and_pages/$1 break;
break;
}
if ($request_uri ~* ^/VSPNOA/(bar_code|out_file_transitStation|file_download_station|file_transitStation|file_preview_scripts|oa_stamp_doc_attachment_file)/(.*)$) {
#图片/附件储存路径
root /var/PROJ_FILE_WAREHOUSE/;
break;
}
if ($request_uri ~* ^/VSPNOA/(.*).+\.(jsp|html|htm)(.*)$) {
#jsp/html/htm页面
proxy_pass http://www.vspnoa.tomcat_colony_main_server;
break;
}
if ($request_uri ~* ^/VSPNOA/(.*).+\.(action|do)(.*)$) {
set $action_proxy_pass http://www.vspnoa.tomcat_colony;
# 使用lua 获取get/post参数
lua_need_request_body on;
rewrite_by_lua_file conf/lua/get_params.lua;
proxy_pass $action_proxy_pass;
break;
}
if ($request_uri ~* ^/VSPNOA/(.*)$) {
proxy_pass http://www.vspnoa.tomcat_colony_main_server;
break;
}
send_timeout 60;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# 启用ngx_pagespeed
pagespeed on;
pagespeed FileCachePath /tmp/cache/ngx_pagespeed_cache;
# 禁用CoreFilters
pagespeed RewriteLevel PassThrough;
# 启用压缩空白过滤器
pagespeed EnableFilters collapse_whitespace;
# 启用JavaScript库卸载
pagespeed EnableFilters canonicalize_javascript_libraries; #谷歌被墙,并不确定这个设置有没有副作用
# 把多个CSS文件合并成一个CSS文件
pagespeed EnableFilters combine_css;
# 把多个JavaScript文件合并成一个JavaScript文件
pagespeed EnableFilters combine_javascript;
# 删除带默认属性的标签
pagespeed EnableFilters elide_attributes;
# 改善资源的可缓存性
pagespeed EnableFilters extend_cache;
# 更换被导入文件的@import,精简CSS文件
pagespeed EnableFilters flatten_css_imports;
pagespeed CssFlattenMaxBytes 5120;
# 延时加载客户端看不见的图片
pagespeed EnableFilters lazyload_images;
# 启用JavaScript缩小机制
pagespeed EnableFilters rewrite_javascript;
# 启用图片优化机制
pagespeed EnableFilters rewrite_images;
# 预解析DNS查询
pagespeed EnableFilters insert_dns_prefetch;
# 重写CSS,首先加载渲染页面的CSS规则
pagespeed EnableFilters prioritize_critical_css;
# 禁止pagespeed 处理WordPress的/wp-admin/目录(可选配置,可参考使用)
pagespeed Disallow "*/wp-admin/*";
# 禁止pagespeed 处理typecho的/admin/目录(可选配置,可参考使用)
pagespeed Disallow "*/admin/*";
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; }
location ~ "^/ngx_pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
location /ngx_pagespeed_statistics { allow 127.0.0.1; deny all; }
location /ngx_pagespeed_message { allow 127.0.0.1; deny all; }
}
在nginx.conf中,引用了 conf/lua/get_params.lua
脚本:
lua_need_request_body on;
rewrite_by_lua_file conf/lua/get_params.lua;
0.5.2. conf/lua/get_params.lua
local action_request_method = ngx.var.request_method
local action_url_param = nil
local action_proxy_upstream = "www.vspnoa.tomcat_colony"
local action_accpted_param_str = nil
if "GET" == action_request_method then
action_accpted_param_str = ngx.req.get_uri_args()
elseif "POST" == action_request_method then
ngx.req.read_body()
action_accpted_param_str = ngx.req.get_post_args()
end
if action_accpted_param_str ~= nil then
action_url_param = action_accpted_param_str["url_param"]
end
if action_url_param ~= nil then
if action_url_param == "get_stf_mastered_element_type_selected_approve_prcs_unfinished_list_with_proj_budg_items" then
action_proxy_upstream = "www.vspnoa.tomcat_approve_process_colony"
elseif action_url_param == "batch_edit_approving_status" then
action_proxy_upstream = "www.vspnoa.tomcat_approve_process_colony"
elseif action_url_param == "edit_approving_status_from_joint" then
action_proxy_upstream = "www.vspnoa.tomcat_approve_process_colony"
elseif action_url_param == "revoke_approve" then
action_proxy_upstream = "www.vspnoa.tomcat_approve_process_colony"
elseif action_url_param == "edit_approving_PRI" then
action_proxy_upstream = "www.vspnoa.tomcat_approve_process_colony"
elseif action_url_param == "edit_expense_element_cashier_payment_plan" then
action_proxy_upstream = "www.vspnoa.tomcat_finance_process_colony"
elseif action_url_param == "edit_expense_element_cashier_payment_exec" then
action_proxy_upstream = "www.vspnoa.tomcat_finance_process_colony"
elseif action_url_param == "batch_insert_and_refer_approving_fc_list" then
action_proxy_upstream = "www.vspnoa.tomcat_finance_process_colony"
end
end
ngx.var.action_proxy_pass=string.format("%s%s","http://",action_proxy_upstream);
-- ngx.log(ngx.INFO , "action_url_param: " , action_url_param);