Ngx_Lua使用分享
1. Nginx_Lua
1.1. 介绍
ngx_lua – 把lua语言嵌入nginx中,使其支持lua来快速开发基于nginx下的业务逻辑
该模块不在nginx源码包中,需自行下载编译安装。使用lua 5.1(目前不支持lua 5.2) 或 luajit 2.0 。
添加lua支持后,开发复杂的模块,周期快,依然是100%异步非阻塞。
ngx_lua 哪些人在用:
淘宝、腾讯财经、网易财经、360、去哪儿网等
CloudFlare, CNN, Wingify, Reblaze, Turner, Broadcasting System
该项目主要开发者:
chaoslawful Taobao, Alibaba Grp.
agentzh CloudFlare
https://github.com/chaoslawful/lua-nginx-module
1.2. 安装
1.2.1. 安装JIT平台
JIT
- 通常,程序有两种运行方式:静态编译与动态直译。
- 静态编译的程序在执行前全部被翻译为机器码,而动态直译执行的则是一句一句边运行边翻译。
- 即时编译(Just-In-Time Compiler)则混合了这二者,一句一句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。
- JAVA、.NET 实现都使用即时编译以提供高速的代码执行。
- 注意:
- 在nginx.conf中添加"lua_code_cache on/off",来开启是否将代码缓存,所以每次变更"*.lua"文件时,必须reload nginx才可生效。
- 仅针对"set_by_lua_file, content_by_lua_file, rewrite_by_lua_file, and access_by_lua_file"有效, 因为其他为写在配置文件
- 中,更改代码也必须reload nginx。在生产环境下,不能禁用cache。同时在lua代码中使用"dofile" 或 "loadfie" 来加载外部lua脚步
- 将不会对它进行缓存,应该使用"require"来代替。禁用cache,当且仅当在调式代码下。
- demo 1
LuaJIT
- 是一个利用JIT编译技术把Lua脚本直接编译成机器码由CPU运行
- 版本:2.0 与 2.1
- 当前稳定版本为 2.0。
- 2.1为版本与ngx_lua将有较大性能提升,主要是CloudFlare公司对luajit的捐赠。
- FFI库,是LuaJIT中最重要的一个扩展库。
- 1. 它允许从纯Lua代码调用外部C函数,使用C数据结构;
- 2. 就不用再像Lua标准math库一样,编写Lua扩展库;
- 3. 把开发者从开发Lua扩展C库(语言/功能绑定库)的繁重工作中释放出来;
- demo 2
下载编译
- wget -c http://luajit.org/download/LuaJIT-2.0.2.tar.gz
- tar xzvf LuaJIT-2.0.2.tar.gz
- cd LuaJIT-2.0.2
- make install PREFIX=/usr/local/luajit
- echo "/usr/local/luajit/lib" > /etc/ld.so.conf.d/usr_local_luajit_lib.conf
- ldconfig
- #注意环境变量!
- export LUAJIT_LIB=/usr/local/luajit/lib
- export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0
1.2.2. NDK与Lua_module
NDK(Nginx Development Kit)模块是一个拓展Nginx服务器核心功能的模块
第三方模块开发可以基于它来快速实现
NDK提供函数和宏处理一些基本任务,减轻第三方模块开发的代码量。
- wget -c https://github.com/simpl/ngx_devel_kit/archive/v0.2.18.tar.gz
- wget -c https://github.com/chaoslawful/lua-nginx-module/archive/v0.8.6.tar.gz
- tar xzvf v0.2.18
- tar xzvf v0.8.6
1.2.3. 编译安装Nginx
- wget -c http://nginx.org/download/nginx-1.4.2.tar.gz
- tar xzvf nginx-1.4.2.tar.gz
- cd nginx-1.4.2
- ./configure --add-module=../ngx_devel_kit-0.2.18/ --add-module=../lua-nginx-module-0.8.6/
- make
- make install
1.3. 嵌入Lua后
1.3.1. 检测版本
- 自己编译官方的 nginx 源码包,只需事前指定 LUAJIT_INC 和 LUAJIT_LIB 这两个环境变量。
- 验证你的 LuaJIT 是否生效,可以通过下面这个接口:
- location = /lua-version {
- content_by_lua '
- if jit then
- ngx.say(jit.version)
- else
- ngx.say(_VERSION)
- end
- ';
- }
- demo 3
- 如果使用的是标准 Lua,访问 /lua-version 应当返回响应体 Lua 5.1
- 如果是 LuaJIT 则应当返回类似 LuaJIT 2.0.2 这样的输出。
- 不要使用标准lua,应当使用luajit, 后者的效率比前者高多了。
- 也可以直接用 ldd 命令验证是否链了 libluajit-5.1 这样的 .so 文件,例如:
- [root@limq5 sbin]# ldd nginx | grep lua
- libluajit-5.1.so.2 => /usr/local/luajit/lib/libluajit-5.1.so.2 (0x00007f48e408b000)
- [root@limq5 sbin]#
1.3.2. Hello,World
在nginx.conf中的service添加一个location。
- location = /test {
- content_by_lua '
- ngx.say("Hello World")
- ngx.log(ngx.ERR, "err err err")
- ';
- }
demo 4
用户访问 http://localhost/test 将会打印出“Hello World”内容。
ngx.say 是 lua 显露給模块的接口。
类似的有 ngx.log(ngx.DEBUG, “”),可以在error.log输出调试信息。
另外也可以调用外部脚本,如同我们写php、jsp应用时,业务脚本单独组织在.php或.jsp文件中一样
- location = /test2 {
- content_by_lua_file conf/lua/hello.lua;
- }
文件hello.lua内容如下:
- ngx.say("Hello World")
这里的脚本可以任意复杂,也可以使用Lua 自己的库
lua可用模块列表:
http://luarocks.org/repositories/rocks/
安装类似yum,它也有一个仓库:
luarocks install luafilesystem
运行上面命令后,会编译一个 “lfs.so”, 文件,拷贝文件到nginx定义的LUA_PATH中,然后引用
该库,就可调用其中函数。
LUA_PATH:
lua_package_path ‘/opt/17173/nginx-ds/conf/lua/?.lua;;’
lua_package_cpath ‘/opt/17173/nginx-ds/conf/lua/lib/?.so;/usr/local/lib/?.?;;’;
其中”;;”代表原先查找范围。
demo 5
1.3.3. 同步形式,异步执行
我们假定,同时要访问多个数据源,而且,查询是没有依赖关系,那我们就可以同时发出请求
这样我总的延时, 是我所有请求中最慢的一个所用时间,而不是原先的所有请求用时的叠加
- location = /api {
- content_by_lua '
- local res1, res2, res3 =
- ngx.location.capture_multi{
- {"/memc"}, {"/mysql"}, {"/postgres"}
- }
- ngx.say(res1.body, res2.body, res3.body)
- ';
- }
- demo 6
- ngx.location.capture 无法跨server进行处理, 只能在同一个server下的不同location。
1.4. Nginx与Lua执行顺序
1.4.1. Nginx顺序
Nginx 处理每一个用户请求时,都是按照若干个不同阶段(phase)依次处理的,而不是根据配置文件上的顺序。
Nginx 处理请求的过程一共划分为 11 个阶段,按照执行顺序依次是
post-read、server-rewrite、find-config、rewrite、post-rewrite、 preaccess、access、post-access、try-files、content、log.
- post-read:
- 读取请求内容阶段
- Nginx读取并解析完请求头之后就立即开始运行
- 例如模块 ngx_realip 就在 post-read 阶段注册了处理程序,它的功能是迫使 Nginx 认为当前请求的来源地址是指定的某一个请求头的值。
- server-rewrite
- Server请求地址重写阶段
- 当 ngx_rewrite 模块的set配置指令直接书写在 server 配置块中时,基本上都是运行在 server-rewrite 阶段
- find-config
- 配置查找阶段
- 这个阶段并不支持 Nginx 模块注册处理程序,而是由 Nginx 核心来完成当前请求与 location 配置块之间的配对工作。
- rewrite
- Location请求地址重写阶段
- 当 ngx_rewrite 模块的指令用于 location 块中时,便是运行在这个 rewrite 阶段。
- 另外,ngx_set_misc(设置md5、encode_base64等) 模块的指令,还有 ngx_lua 模块的 set_by_lua 指令和 rewrite_by_lua 指令也在此阶段。
- post-rewrite
- 请求地址重写提交阶段
- 由 Nginx 核心完成 rewrite 阶段所要求的“内部跳转”操作,如果 rewrite 阶段有此要求的话。
- preaccess
- 访问权限检查准备阶段
- 标准模块 ngx_limit_req 和 ngx_limit_zone 就运行在此阶段,前者可以控制请求的访问频度,而后者可以限制访问的并发度。
- access
- 访问权限检查阶段
- 标准模块 ngx_access、第三方模块 ngx_auth_request 以及第三方模块 ngx_lua 的 access_by_lua 指令就运行在这个阶段。
- 配置指令多是执行访问控制性质的任务,比如检查用户的访问权限,检查用户的来源 IP 地址是否合法
- post-access
- 访问权限检查提交阶段
- 主要用于配合 access 阶段实现标准 ngx_http_core 模块提供的配置指令 satisfy 的功能。
- satisfy all(与关系)
- satisfy any(或关系)
- try-files
- 配置项try_files处理阶段
- 专门用于实现标准配置指令 try_files 的功能
- 如果前 N-1 个参数所对应的文件系统对象都不存在,try-files 阶段就会立即发起“内部跳转”到最后一个参数(即第 N 个参数)所指定的 URI.
- content
- 内容产生阶段
- Nginx 的 content 阶段是所有请求处理阶段中最为重要的一个,因为运行在这个阶段的配置指令一般都肩负着生成“内容”
- 并输出 HTTP 响应的使命。
- log
- 日志模块处理阶段
- 记录日志
淘宝有开放一个nginx开发手册,里面包含很多有用的资料
http://tengine.taobao.org/book/
作者的google论坛:
https://groups.google.com/forum/#!forum/openresty
1.4.2. Lua顺序
Nginx下Lua处理阶段与使用范围:
- init_by_lua http
- set_by_lua server, server if, location, location if
- rewrite_by_lua http, server, location, location if
- access_by_lua http, server, location, location if
- content_by_lua location, location if
- header_filter_by_lua http, server, location, location if
- body_filter_by_lua http, server, location, location if
- log_by_lua http, server, location, location if
- timer
- init_by_lua:
- 在nginx重新加载配置文件时,运行里面lua脚本,常用于全局变量的申请。
- 例如lua_shared_dict共享内存的申请,只有当nginx重起后,共享内存数据才清空,这常用于统计。
- set_by_lua:
- 设置一个变量,常用与计算一个逻辑,然后返回结果
- 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API
- rewrite_by_lua:
- 在access阶段前运行,主要用于rewrite
- access_by_lua:
- 主要用于访问控制,能收集到大部分变量,类似status需要在log阶段才有。
- 这条指令运行于nginx access阶段的末尾,因此总是在 allow 和 deny 这样的指令之后运行,虽然它们同属 access 阶段。
- content_by_lua:
- 阶段是所有请求处理阶段中最为重要的一个,运行在这个阶段的配置指令一般都肩负着生成内容(content)并输出HTTP响应。
- header_filter_by_lua:
- 一般只用于设置Cookie和Headers等
- 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API
- body_filter_by_lua:
- 一般会在一次请求中被调用多次, 因为这是实现基于 HTTP 1.1 chunked 编码的所谓“流式输出”的。
- 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API
- log_by_lua:
- 该阶段总是运行在请求结束的时候,用于请求的后续操作,如在共享内存中进行统计数据,如果要高精确的数据统计,应该使用body_filter_by_lua。
- 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API
- timer:
可参考官方文档:
http://wiki.nginx.org/HttpLuaModule
2. Lua基本语法
2.1. 关键字
- and break do else elseif
- end false for function if
- in local nil not or
- repeat return then true until while
2.2. 运算
2.2.1. 数字运算
- 支持 +, -, *, /,^ 比如2^3 结果为8, 2^4结果为16。
- 连接两个字符串,用".."运处符, php为".", JAVA、C#为"+"
2.2.2. 赋值运算
- a,b,c,d=1,2,3,4 -- 多变量一起赋值
- a,b=b,a --交换变量功能
- 在默认情况下,变量总是认为是全局的。假如需要定义局部变量,则在第一次赋值的时候,需要用local说明。比如:
- local a,b,c = 1,2,3 -- a,b,c都是局部变量
2.2.3. 逻辑运算
- and, or, not
- 在Lua中,只有false和nil才计算为false,其它任何数据都计算为true,0也是true
- and 和 or的运算结果不是true和false,而是和它的两个操作数相关。
- a and b:如果a为false,则返回a;a true 返回b
- a or b:如果 a 为true,则返回a;a false 返回b
- 模拟C语言中的语句:x = a? b : c,在Lua中,可以写成:x = a and b or c。
- 最有用的语句是: x = x or v,它相当于:if not x then x = v end 。
2.3. 条件判断语句
2.3.1. if
- if 条件 then
- ...
- elseif 条件 then
- ... else ...
- end
2.3.2. repeat
- repeat ... until 条件
2.3.3. while
- while 条件
- do
- ...
- end
2.3.4. for
- for 变量=初值, 终点值, 步进
- do
- ...
- end
- for 变量1, 变量2, ... 变量n in 表或枚举函数
- do
- ...
- end
2.4. 常用结构
2.4.1. table
- 1. table 是 lua 中最重要的数据类型。
- 2. table 类似于 python 中的字典。
- 3. table 只能通过构造式来创建
;例1
- Lua代码
- tab = { a = 10, b = 20, c = 30, d = 40 }
- print(tab["a"])
- 注释:
- 1)table 中的每项要求是 key = value 的形式
- 2)key 只能是字符串, 这里的 a, b, c, d 都是字符串,但是不能加上引号
- 3)通过 key 来访问 table 的值,这时候, a 必须加上引号
;例2
- tab = { 10, m = 20, 11, 12, 13 }
- print(tab[1]) = 10
- print(tab[2]) = 11
- print(tab[3]) = 12
- print(tab[4]) = 13
- 获取表长度:
- print(table.getn(tab)) -> 4
- print(#tab) -> 4
- 遍历表:
- for k, v in pairs(tab) do
- print(k, ":", v)
- end
- 1 : 10
- 2 : 11
- 3 : 12
- 4 : 13
- m : 20
- 注释:
- 1)省略key,会自动以1开始编号,并跳过设置过的key
- 2)获取表长度,只有当表使用1自动编号开始,可以获取
2.4.2. lua表空判断
在项目的脚本lua中经常有这样的需求
- local a = {}
- 判断表a是否为空,有提供api table.maxn(a) 或 #a 获取表a长度,但是该情况只
- 针对key为数字且安装递增方式。
- 对于自定义key的情况下,获取表长度将会失败,可通过lua内置 next函数解决该问题。
2.5. 参考
- lua官方手册 http://www.lua.org/manual/5.1/
- lua中文翻译手册 http://www.codingnow.com/2000/download/lua_manual.html
- 转载:http://17173ops.com/2013/11/01/17173-ngx-lua-manual.shtml
Ngx_Lua使用分享的更多相关文章
- (转)Ngx_Lua使用分享
原文:https://www.cnblogs.com/yanzi-meng/p/9450999.html ngx_lua 模块详细讲解(基于openresty)---https://www.cnblo ...
- openresty(nginx)、lua、drizzle调研
一.概述: 1.研究目标:nginx中使用lua脚本,及nginx直接访问mysql,redis 2.需要安装的内容: openresty,mysql,redis 3.OpenResty (也称为 n ...
- Lua:Nginx Lua环境配置,第一个Nginx Lua代码
一.编译安装LuaJIT Lua:编译安装LuaJIT,第一个Lua程序 http://blog.csdn.net/guowenyan001/article/details/48250427 二.下载 ...
- nginx限制请求之三:Nginx+Lua+Redis 对请求进行限制
相关文章: <高可用服务设计之二:Rate limiting 限流与降级> <nginx限制请求之一:(ngx_http_limit_conn_module)模块> <n ...
- 【实战分享】又拍云 OpenResty / Nginx 服务优化实践
2018 年 11 月 17 日,由 OpenResty 主办的 OpenResty Con 2018 在杭州举行.本次 OpenResty Con 的主题涉及 OpenResty 的新开源特性.业界 ...
- ngx_lua应用最佳实践
引子: 以下文字,是UPYUN系统开发工程师timebug在SegmentFault D-Day南京站技术沙龙上所做分享的内容要义提炼,主题为UPYUN系统开发团队在进行业务逻辑由C模块到ngx_lu ...
- 专訪阿里陶辉:大规模分布式系统、高性能server设计经验分享
http://www.csdn.net/article/2014-06-27/2820432 摘要:先后就职于在国内知名的互联网公司,眼下在阿里云弹性计算部门做架构设计与核心模块代码的编写,主要负责云 ...
- .net点选验证码实现思路分享
哈哈好久没冒泡了,最进看见点选验证码有点意思,所以想自己写一个. 先上效果图 如果你被这个效果吸引了就请继续看下去. 贴代码前先说点思路: 1.要有一个汉字库,并按字形分类.(我在数据库里是安部首分类 ...
- Hangfire项目实践分享
Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...
随机推荐
- centos 7 删除yum安装的openjdk
# java -version # rpm -qa | grep java rpm -e --nodeps (rpm -qa的结果们) # java -version
- Ubuntu下eclipse中运行Hadoop时所需要的JRE与JDK的搭配
第一组: Eclise 版本:Indigo,Service Release 1 Build id:20110916-0149 Window-->Preferences -->Compile ...
- 1.7Oob成员变量和局部变量疑难区分
import java.util.Scanner; public class booleann { private float fWidth; private float fHeight; void ...
- 网络层block,delegate之优劣分析
正常情况下, block 缺点: 1.block很难追踪,难以维护 2.block会延长先关对象的生命周期 block会给内部所有的对象引用计数+1, 一方面会带来潜在的循环引用(retain cyc ...
- MySQL服务器线程数的查看方法详解
本文实例讲述了MySQL服务器线程数的查看方法.分享给大家供大家参考,具体如下: mysql重启命令: ? 1 /etc/init.d/mysql restart MySQL服务器的线程数需要在一个合 ...
- [tcpreplay] tcpreplay高级用法--使用tcpreplay-edit进行循环动态发包
tcpreplay-edit提供了可对包进行修改的高级用法: --unique-ip Modify IP addresses each loop iteration to generate uniqu ...
- isprime_判断质数
判断质数的方法有很多,首先是最简单的试除法,判断n以内的质数的话时间复杂度为n*sqrt(n)当然是很慢的了 下面提供三种判断质数的方法: 首先是跑5051ms的这个是埃拉托斯特尼筛法 且不加优化 核 ...
- 内部排序->其它->地址排序(地址重排算法)
文字描述 当每个记录所占空间较多,即每个记录存放的除关键字外的附加信息太大时,移动记录的时间耗费太大.此时,就可以像表插入排序.链式基数排序,以修改指针代替移动记录.但是有的排序方法,如快速排序和堆排 ...
- LeetCode 682 Baseball Game 解题报告
题目要求 You're now a baseball game point recorder. Given a list of strings, each string can be one of t ...
- python之文件操作的函数
file=open("e:\\c.py","w",encoding="utf-8")date=file.close() ...