OpenResty基础

介绍

基础

OpenResty常见API

输出响应

1
2
3
4
location /lua_response{
default_type 'text/html';
content_by_lua_file lua/lua_response.lua ;
}

lua_response.lua代码:

1
2
3
4
5
ngx.header.a="1"
ngx.header.b={"a","b"}
ngx.say("hello","</br>")
ngx.print("wanglibing")
return ngx.exit(200)

API 说明
ngx.header 向响应头输出内容
ngx.say 输出响应体
ngx.print 输出响应体
ngx.exit 指定http状态码退出
1
$ curl ‘http://127.0.0.1/lua_response’

返回结果:

1
2
hello
wanglibing

获取请求参数(ngx.var)

ngx.var用于获取请求的参数。

1
2
3
4
5
6
location /lua_var {
default_type 'text/plain';
content_by_lua_block {
ngx.say(ngx.var.arg_a)
}
}

在浏览器上访问http://127.0.0.1/lua_var?a=123

获取请求头(ngx.req.get_headers())

lua_request.lua代码如下

1
2
3
4
5
6
7
8
9
10
11
12
local headers = ngx.req.get_headers()
ngx.say("headers begin", "<br/>")
ngx.say("Host : ", headers["Host"], "<br/>")
ngx.say("user-agent : ", headers["user-agent"], "<br/>")
ngx.say("user-agent : ", headers.user_agent, "<br/>")
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

使用curl模拟请求:

1
$ curl ‘http://127.0.0.1/lua_request?a=123&b=zhangsan -d 'c=lisi&d=wangwu'

返回结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
[GET ] key:b v:zhangsan
[GET ] key:a v:123
[POST] key:d v:wangwu
[POST] key:c v:lisi
headers begin<br/>
Host : 192.168.0.14<br/>
user-agent : curl/7.53.0<br/>
user-agent : curl/7.53.0<br/>
host : 192.168.0.14<br/>
content-type : application/x-www-form-urlencoded<br/>
accept : */*<br/>
content-length : 12<br/>
user-agent : curl/7.53.0<br/>

获取请求类型(ngx.req)

1
2
3
4
location /lua_request{
default_type 'text/html';
content_by_lua_file /lua/lua_request.lua;
}

lua_request.lua代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local arg = ngx.req.get_uri_args()
for k,v in pairs(arg) do
ngx.say("[GET ] key:", k, " v:", v)
end

-- 解析 body 参数之前一定要先读取 body
ngx.req.read_body()
local arg = ngx.req.get_post_args()
for k,v in pairs(arg) do
ngx.say("[POST] key:", k, " v:", v)
end
ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "<br/>")
--请求方法
ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "<br/>")
--原始的请求头内容
ngx.say("ngx.req.raw_header : ", ngx.req.raw_header(), "<br/>")
--请求的body内容体
ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "<br/>")
ngx.say("<br/>")

使用curl模拟请求:

1
$ curl ‘http://127.0.0.1/lua_request?a=123&b=zhangsan -d 'c=lisi&d=wangwu'

返回的结果:

1
2
3
4
5
6
7
8
9
10
11
[GET ] key:b v:zhangsan
[GET ] key:a v:123
[POST] key:d v:wangwu
[POST] key:c v:lisi
ngx.req.http_version : 1.1<br/>
ngx.req.get_method : POST<br/>
ngx.req.raw_header : POST /lua_request?a=323&b=ss HTTP/1.1
Host: 192.168.0.14
User-Agent: curl/7.53.0
Accept: */*
Content-Length: 12

API 说明
ngx.req.get_uri_args 获取在uri上的get类型参数,返回的是一个table类型的数据结构
ngx.req.read_body 读取body
ngx.req.get_post_args 获取form表单类型的参数,返回结果是一个table类型的数据
ngx.req.get_headers() 获取请求头
ngx.req.http_version 获取 http 版本
ngx.req.get_method 获取请求方法
ngx.req.raw_header 获取请求头(包括请求行)
ngx.req.get_body_data() 获取请求的body内容体

重定向

1
2
3
4
location /lua_redirect{
default_type 'text/html';
content_by_lua_file lua/lua_redirect.lua;
}

lua_redirect.lua代码:

1
ngx.redirect("https://www.wanglibing.com", 302)

http://127.0.0.1/lua_redirect

日志输出

1
2
3
4
location /lua_log{
default_type 'text/html';
content_by_lua_file lua/lua_log.lua;
}

lua_log.lua代码:

1
2
3
4
local log="i'm log"
local num =10
ngx.log(ngx.ERR, "log",log)
ngx.log(ngx.INFO,"num:" ,num)

1
$ curl 'http://127.0.0.1/lua_log'
日志级别 说明
ngx.STDERR 标准输出
ngx.EMERG 紧急报错
ngx.ALERT 报警
ngx.CRIT 严重,系统故障,触发运维告警系统
ngx.ERR 错误,业务不可恢复性错误
ngx.WARN 告警,业务中可忽略错误
ngx.NOTICE 提醒,业务比较重要信息
ngx.INFO 信息,业务琐碎日志信息,包含不同情况判断等
ngx.DEBUG 调试

共享内存

修改nginx.conf,在http模块加上以下:

1
lua_shared_dict shared_data 1m;

1
2
3
4
location /lua_shared_dict{
default_type 'text/html';
content_by_lua_file lua/lua_shared_dict.lua;
}

lua_shared_dict.lua代码:

1
2
3
4
5
6
7
8
local shared_data = ngx.shared.shared_data
local i = shared_data:get("i")
if not i then
i = 1
shared_data:set("i",i)
end
i = shared_data:incr("i",1)
ngx.say("i:",i)

多次访问 http://127.0.0.1/lua_shared_dict 返回结果:

1
2
3
4
5
i:1
i:2
i:3
i:4
i:5

内部调用

internal 关键字,表示只允许内部调用。

1
2
3
4
5
6
7
8
9
10
location /lua_sum{
# 只允许内部调用
internal;
# 这里做了一个求和运算只是一个例子,可以在这里完成一些数据库、
# 缓存服务器的操作,达到基础模块和业务逻辑分离目的
content_by_lua_block {
local args = ngx.req.get_uri_args()
ngx.say(tonumber(args.a) + tonumber(args.b))
}
}

使用curl模拟请求:

1
$ curl 'http://127.0.0.1/lua_sum?a=1&b=2'

由于该loction是一个内部调用的,外部不能返回,最终返回的结果为404。 修改代码:

1
2
3
4
5
6
location = /lua_sum_test {
content_by_lua_block {
local res = ngx.location.capture("/lua_sum", {args={a=3, b=8}})
ngx.say("status:", res.status, " response:", res.body)
}
}

上述的代码通过ngx.location.capture去调用内部的location,并获得返回结果,最终将结果输出,采用curl模拟请求:

1
$ curl 'http://127.0.0.1/lua_sum_test'

返回结果:

1
status:200 response:11

总结

API 说明
ngx.header 向响应头输出内容
ngx.say 输出响应体
ngx.print 输出响应体
ngx.exit 指定http状态码退出
ngx.var 获取请求参数
ngx.req.get_uri_args 获取在uri上的get类型参数,返回的是一个table类型的数据结构
ngx.req.read_body 读取body
ngx.req.get_post_args 获取form表单类型的参数,返回结果是一个table类型的数据
ngx.req.get_headers() 获取请求头
ngx.req.http_version 获取 http 版本
ngx.req.get_method 获取请求方法
ngx.req.raw_header 获取请求头(包括请求行)
ngx.req.get_body_data() 获取请求的body内容体
ngx.redirect("url",code) 重定向
ngx.log() 输出日志信息到error.log
ngx.shared.shared_data 设置一个共享全局变量表,在所有worker进程间共享

OpenResty执行阶段

阶段

阶段 说明
NGX_HTTP_POST_READ_PHASE 读取请求内容阶段
NGX_HTTP_SERVER_REWRITE_PHASE Server请求地址重写阶段
NGX_HTTP_FIND_CONFIG_PHASE 配置查找阶段
NGX_HTTP_REWRITE_PHASE Location请求地址重写阶段
NGX_HTTP_POST_REWRITE_PHASE 请求地址重写提交阶段
NGX_HTTP_PREACCESS_PHASE 访问权限检查准备阶段
NGX_HTTP_ACCESS_PHASE 访问权限检查阶段
NGX_HTTP_POST_ACCESS_PHASE 访问权限检查提交阶段
NGX_HTTP_TRY_FILES_PHASE 配置项try_files处理阶段
NGX_HTTP_CONTENT_PHASE 内容产生阶段
NGX_HTTP_LOG_PHASE 日志模块处理阶段

流程图

openresty_phases.png
openresty_phases.png

有些阶段是支持 Nginx 模块注册处理程序,有些阶段并不可以。 Nginx 的conf中指令的书写顺序和执行顺序是两码事。 有些指令虽然在同一个阶段,执行的顺序也可能是无法预测的,使用之前请认真阅读文档和测试。

最常用的是 rewrite阶段、access阶段、以及content阶段,不支持 Nginx 模块注册处理程序的阶段 find-config、post-rewrite、post-access、主要是 Nginx 核心完成自己的一些逻辑。

常见7个阶段

阶段 说明
set_by_lua 流程分支处理判断变量初始化
rewrite_by_lua 常用来改写 url等,转发、重定向、缓存等功能(例如特定请求代理到外网)
access_by_lua IP准入、接口权限等情况集中处理(例如配合iptable完成简单防火墙)
content_by_lua 内容生成
header_filter_by_lua 应答HTTP过滤处理(例如添加头部信息)
body_filter_by_lua 应答BODY过滤处理(例如完成应答内容统一成大写)
log_by_lua 会话完成后本地异步完成日志记录(日志可以记录在本地,还可以同步到其他机器)

安装

包管理安装

安装

1
2
3
$ yum -y install yum-utils
$ yum-config-manager --add-repo https://openresty.org/yum/cn/centos/OpenResty.repo
$ yum install -y openresty

配置环境变量

1
$ vi /etc/profile

添加如下内容:

1
export PATH=/usr/local/openresty/nginx/sbin:$PATH

1
$ source /etc/profile

源码安装

安装依赖

1
$ yum install -y pcre-devel openssl-devel gcc curl

安装openresty

1
2
3
4
5
6
7
8
9
10
11
$ cd /usr/local
$ wget https://openresty.org/download/openresty-1.13.6.2.tar.gz
$ tar zxvf openresty-1.13.6.2.tar.gz
$ mv openresty-1.13.6.2 openresty
$ cd openresty
$ ./configure --prefix=/opt/openresty \
--with-luajit \
--without-http_redis2_module \
--with-http_iconv_module
$ gmake
$ gmake install
1
$ ./configure

默认, --prefix=/usr/local/openresty 程序会被安装到/usr/local/openresty目录。您可以指定各种选项,比如

1
2
3
4
5
./configure --prefix=/opt/openresty \
--with-luajit \
--without-http_redis2_module \
--with-http_iconv_module \
--with-http_postgres_module

试着使用

1
./configure --help

查看更多的选项。

如果您的电脑支持多核 make 工作的特性, 您可以这样编译:

1
$ make -j2

假设您是的机器是双核。

配置环境变量

1
$ vi /etc/profile

添加如下内容:

1
export PATH=/opt/openresty/nginx/sbin:$PATH

1
$ source /etc/profile

HomeBrew安装

安装OpenResty

1
$ brew install openresty/brew/openresty

配置环境变量

1
export PATH=/usr/local/opt/openresty/nginx/sbin:$PATH

操作OpenResty

启动Nginx

1
$ sudo nginx

停止Nginx

1
$ sudo nginx -s stop

停止nginx也停止了openresty。

重启Nginx

1
$ sudo nginx -s reload

检验nginx配置是否正确

1
$ sudo nginx -t

开发

创建OpenResty项目

目录结构

1
2
3
4
5
6
7
8
9
10
11
|- project                         |- 项目目录
|- conf |- 配置文件目录
|- nginx-dev.conf |- 开发环境配置文件
|- nginx.conf |- 生产环境配置文件
|- logs |- 日志目录
|- error.log |- 日志文件
|- lua |- Lua文件目录
|- index.lua |- 入口文件
|- lualib |- 第三方库目录
|- *.lua
|- *.so

创建OpenResty项目步骤

初始化项目

1
2
$ mkdir project project/conf/ project/logs/ project/lua/ project/lualib/ 
$ touch project/conf/nginx-dev.conf project/conf/nginx.conf project/logs/error.log project/lua/index.lua

将项目重命名

1
$ mv project newProject

配置nginx-dev.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
worker_processes  1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
lua_package_path "lualib/?.lua;;";
lua_package_cpath "lualib/?.so;;";
server {
listen 8085;
location / {
default_type text/html;
lua_code_cache off;
content_by_lua_file lua/index.lua;
}
}
}
  • lua_package_path 设置纯 Lua 扩展库的搜寻路径(';;' 是默认路径)
  • lua_package_cpath 设置 C 编写的 Lua 扩展模块的搜寻路径(也可以用 ';;')
  • 默认情况下 lua_code_cache 是开启的,即缓存lua代码,即每次lua代码变更必须reload nginx才生效,如果在开发阶段可以通过以下方式关闭缓存。
  • content_by_lua_file指定脚本路径。此处为相对路径,相对于nginx根目录。
1
2
3
4
5
location / {
default_type text/html;
lua_code_cache off;
content_by_lua_file lua/index.lua;
}

这样调试时每次修改lua代码不需要reload nginx,但是正式环境一定记得开启缓存。关闭缓存后会看到如下报警:

1
nginx: [alert] lua_code_cache is off; this will hurt performance in ./conf/nginx.conf:11

配置nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
worker_processes  1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
lua_package_path "lualib/?.lua;;";
lua_package_cpath "lualib/?.so;;";
server {
listen 8085;
location / {
default_type text/html;
lua_code_cache on;
content_by_lua_file lua/index.lua;
}
}
}

nginx.conf为生产环境配置文件,在生产环境中,一定要确保缓存(lua_code_cache)为开启状态(on)。

配置index.lua

1
ngx.say("<p>hello, world</p>");

启动nginx

切换到/project目录下,执行命令:

1
$ nginx -p ./ -c conf/nginx-dev.conf

测试

访问 http://localhost:8085

OpenResty使用http模块

下载lua-resty-http

Openresty没有提供默认的Http客户端,需要下载第三方的http客户端。

1
2
3
$ cd project/lualib/resty/
$ wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_headers.lua
$ wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http.lua

lua-resty-http模块的地址为 https://github.com/pintsized/lua-resty-http

配置http_test.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
local http = require("resty.http")  

local httpc = http.new()

local resp, err = httpc:request_uri("http://s.taobao.com", {
method = "GET",
path = "/search?q=hello",
headers = {
["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"
}
})

if not resp then
ngx.say("request error :", err)
return
end

ngx.status = resp.status

for k, v in pairs(resp.headers) do
if k ~= "Transfer-Encoding" and k ~= "Connection" then
ngx.header[k] = v
end
end

ngx.say(resp.body)

httpc:close()

配置nginx-dev.config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
worker_processes  1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
lua_package_path "lualib/?.lua;;";
lua_package_cpath "lualib/?.so;;";
server {
listen 8085;
location / {
default_type text/html;
lua_code_cache off;
content_by_lua_file lua/index.lua;
}
location /lua_http {
resolver 8.8.8.8;
default_type text/html;
lua_code_cache off;
content_by_lua_file lua/http_test.lua;
}
}
}

测试

访问 http://localhost:8085/lua_http

OpenResty使用lua_cjson模块

openresty默认内嵌了lua_cjson模块,用来序列化数据。 lua_cjson模块的地址:https://www.kyne.com.au/~mark/software/lua-cjson-manual.html

配置cjson_test.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
local cjson = require("cjson")  

local obj = {
id = 1,
name = "zhangsan",
age = nil,
is_male = false,
hobby = {"film", "music", "read"}
}

local str = cjson.encode(obj)
ngx.say(str, "<br/>")


str = '{"hobby":["film","music","read"],"is_male":false,"name":"zhangsan","id":1,"age":null}'
local obj = cjson.decode(str)

ngx.say(obj.age, "<br/>")
ngx.say(obj.age == nil, "<br/>")
ngx.say(obj.age == cjson.null, "<br/>")
ngx.say(obj.hobby[1], "<br/>")

配置nginx-dev.conf

1
2
3
4
5
location ~ /lua_cjson {  
default_type 'text/html';
lua_code_cache off;
content_by_lua_file lua/cjson_test.lua;
}

测试

访问 http://localhost:8085/lua_cjson 返回结果:

1
2
3
4
5
{"is_male":false,"name":"zhangsan","hobby":["film","music","read"],"id":1}
null
false
true
film

OpenResty模块开发

为什么要进行模块开发

模块化开发可以降低软件的复杂性,使其可控、可维护、可扩展。 lua模块开发的模块化开发简单的说是将特定功能的放在一个lua文件中。

OpenResty的默认模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
lualib/
├── cjson.so
├── ngx
│ ├── balancer.lua
│ ├── ocsp.lua
│ ├── re.lua
│ ├── semaphore.lua
│ ├── ssl
│ │ └── session.lua
│ └── ssl.lua
├── rds
│ └── parser.so
├── redis
│ └── parser.so
└── resty
├── aes.lua
├── core
│ ├── base64.lua
│ ├── base.lua
│ ├── ctx.lua
│ ├── exit.lua
│ ├── hash.lua
│ ├── misc.lua
│ ├── regex.lua
│ ├── request.lua
│ ├── response.lua
│ ├── shdict.lua
│ ├── time.lua
│ ├── uri.lua
│ ├── var.lua
│ └── worker.lua
├── core.lua
├── dns
│ └── resolver.lua
├── limit
│ ├── conn.lua
│ ├── req.lua
│ └── traffic.lua
├── lock.lua
├── lrucache
│ └── pureffi.lua
├── lrucache.lua
├── md5.lua
├── memcached.lua
├── mysql.lua
├── random.lua
├── redis.lua
├── sha1.lua
├── sha224.lua
├── sha256.lua
├── sha384.lua
├── sha512.lua
├── sha.lua
├── string.lua
├── upload.lua
├── upstream
│ └── healthcheck.lua
└── websocket
├── client.lua
├── protocol.lua
└── server.lua

在使用这些模块之前,需要在nginx的配置文件nginx.conf中的http模块加上以下的配置:

1
2
lua_package_path "lualib/?.lua;;";
lua_package_cpath "lualib/?.so;;";

开发一个新模块的步骤

创建模块文件

/project/lualib/module1.lua代码:

1
2
3
4
5
6
7
8
9
10
11
local count = 0  
local function hello()
count = count + 1
ngx.say("count : ", count)
end

local _M = {
hello = hello
}

return _M

创建模块调用文件

/project/lua/module_test.lua代码:

1
2
3
local module1 = require("module1")  

module1.hello()

  • 通过require(“模块名”)来加载模块
  • 如果是多级目录,则需要通过require(“目录1.目录2.模块名”)加载。

配置nginx-dev.conf

1
2
3
4
5
location /module1_test {  
default_type 'text/html';
lua_code_cache on;
content_by_lua_file lua/module1_test.lua;
}

测试

访问 http://localhost:8085/module1_test

OpenResty连接MySQL

lua-resty-mysql模块介绍

  • lua-resty-mysql模块是基于cosocket API 为ngx_lua提供的一个Lua MySQL客户端。
  • 它保证了100%非阻塞。
  • 官方文档地址: https://github.com/openresty/lua-resty-mysql

连接MySQL步骤

配置lua/mysql_test.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
local function close_db(db)  
if not db then
return
end
db:close()
end

local mysql = require("resty.mysql")

local db, err = mysql:new()
if not db then
ngx.say("new mysql error : ", err)
return
end

db:set_timeout(1000)

local props = {
host = "192.168.0.14",
port = 3306,
database = "mysql",
user = "root",
password = "123456"
}

local res, err, errno, sqlstate = db:connect(props)

if not res then
ngx.say("connect to mysql error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end

local drop_table_sql = "drop table if exists test"
res, err, errno, sqlstate = db:query(drop_table_sql)
if not res then
ngx.say("drop table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end

local create_table_sql = "create table test(id int primary key auto_increment, ch varchar(100))"
res, err, errno, sqlstate = db:query(create_table_sql)
if not res then
ngx.say("create table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end

local insert_sql = "insert into test (ch) values('hello')"
res, err, errno, sqlstate = db:query(insert_sql)
if not res then
ngx.say("insert error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end

res, err, errno, sqlstate = db:query(insert_sql)

ngx.say("insert rows : ", res.affected_rows, " , id : ", res.insert_id, "<br/>")

local update_sql = "update test set ch = 'hello2' where id =" .. res.insert_id
res, err, errno, sqlstate = db:query(update_sql)
if not res then
ngx.say("update error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end

ngx.say("update rows : ", res.affected_rows, "<br/>")

local select_sql = "select id, ch from test"
res, err, errno, sqlstate = db:query(select_sql)
if not res then
ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end


for i, row in ipairs(res) do
for name, value in pairs(row) do
ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")
end
end

ngx.say("<br/>")

local ch_param = ngx.req.get_uri_args()["ch"] or ''

local query_sql = "select id, ch from test where ch = " .. ngx.quote_sql_str(ch_param)
res, err, errno, sqlstate = db:query(query_sql)
if not res then
ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end

for i, row in ipairs(res) do
for name, value in pairs(row) do
ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")
end
end

local delete_sql = "delete from test"
res, err, errno, sqlstate = db:query(delete_sql)
if not res then
ngx.say("delete error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end

ngx.say("delete rows : ", res.affected_rows, "<br/>")

close_db(db)

配置nginx-dev.conf

1
2
3
4
5
location /mysql_test {
default_type 'text/html';
lua_code_cache off;
content_by_lua_file lua/mysql_test.lua;
}

测试

访问 http://localhost:8085/mysql_test 返回结果:

1
2
3
4
5
6
7
8
insert rows : 1 , id : 2
update rows : 1
select row 1 : ch = hello
select row 1 : id = 1
select row 2 : ch = hello2
select row 2 : id = 2

delete rows : 2

OpenResty连接Redis

lua_resty_redis模块介绍

  • 基于cosocket API的为ngx_lua模块提供Lua redis客户端的驱动。
  • 模块地址:https://github.com/openresty/lua-resty-redis

连接Redis步骤

配置/lua/redis_test.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
local function close_redis(red)  
if not red then
return
end

local pool_max_idle_time = 10000 --毫秒
local pool_size = 100 --连接池大小
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
ngx.say("set keepalive error : ", err)
end
end

local redis = require("resty.redis")


local red = redis:new()

red:set_timeout(1000)

local ip = "192.168.0.14"
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then
ngx.say("connect to redis error : ", err)
return close_redis(red)
end

-- 如果需要验证口令,则需要在这里配置密码
-- local res, err = red:auth(“Redis密码”)

ok, err = red:set("msg", "hello world")
if not ok then
ngx.say("set msg error : ", err)
return close_redis(red)
end


local resp, err = red:get("msg")
if not resp then
ngx.say("get msg error : ", err)
return close_redis(red)
end

if resp == ngx.null then
resp = ''
end
ngx.say("msg : ", resp)

close_redis(red)

配置nginx-dev.conf

1
2
3
4
5
location /redis_test {  
default_type 'text/html';
lua_code_cache off;
content_by_lua_file lua/redis_test.lua;
}

测试

访问 http://localhost:8085/redis_test 返回结果:

1
msg : hello world

学习资料

Nginx

Lua

  1. Lua 教程
  2. LUA简明教程
  3. Lua教程
  4. Lua程序设计

OpenResty

nginx-lua-module使用

  1. https://github.com/iresty/nginx-lua-module-zh-wiki
  2. https://github.com/openresty/lua-nginx-module#readme

OPENRESTY学习系列

技术文章

开源项目

ABTestingGateway

ABTestingGateway是一个可以动态设置分流策略的灰度发布系统,工作在7层,基于nginx和ngx-lua开发,使用 redis 作为分流策略数据库,可以实现动态调度功能。 - 支持多种分流方式,目前包括iprange、uidrange、uid尾数和指定uid分流 - 动态设置分流策略,即时生效,无需重启 - 可扩展性,提供了开发框架,开发者可以灵活添加新的分流方式,实现二次开发 - 高性能,压测数据接近原生nginx转发 - 灰度系统配置写在nginx配置文件中,方便管理员配置 - 适用于多种场景:灰度发布、AB测试和负载均衡等 - new feature: 支持多级分流

https://github.com/CNSRE/ABTestingGateway

vanilla

An OpenResty Lua MVC Web Framework https://github.com/idevz/vanilla

Mio

基于OpenResty/ngx_lua的NGINX的API统计/汇总和健康数据,就像NGINX Plus一样。 Mio的第一个目标是为NGINX提供强大的API统计数据和摘要。 度量标准只是基础,最终目标是用数据的力量自动改进用户的NGINX系统。 https://github.com/iresty/Mio

timebug

https://github.com/timebug

flowlimit

用于部署在OpenResty上的分流限流控制脚本,基于配置策略进行工作,可以通过管理URI实时调整配置生效。 http://git.oschina.net/kevin158/flowlimit

VeryNginx

VeryNginx 基于 lua_nginx_module(openrestry) 开发,实现了高级的防火墙、访问统计和其他的一些功能。 集成在 Nginx 中运行,扩展了 Nginx 本身的功能,并提供了友好的 Web 交互界面。 https://github.com/alexazhou/VeryNginx

lor

lor是一个运行在OpenResty上的基于Lua编写的Web框架.

  • 路由采用Sinatra风格,结构清晰,易于编码和维护.
  • API借鉴了Express的思路和设计,Node.js跨界开发者可以很快上手.
  • 支持多种路由,路由可分组,路由匹配支持正则模式.
  • 支持middleware机制,可在任意路由上挂载中间件.
  • 可作为HTTP API Server,也可用于构建传统的Web应用.

https://github.com/sumory/lor

openresty-china

一个运行在OpenResty上的基于lor编写的社区软件。

  • 主要页面直接采用了ruby-china的样式
  • 完全基于OpenResty,是入门OpenResty Web开发的良好范例
  • 基于Lor Framework,轻松简单的开发Sinatra风格的web应用
  • 存储采用MySQL,文件本地落地存储

https://github.com/sumory/openresty-china

GitHub资源

  1. awesome-resty A List of OpenResty / Nginx modules, Lua libraries, and related resources.
  2. lua-nginx-module ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. This module is not distributed with the Nginx source.

社区

OpenResty China

PPT

  1. Using ngx_lua in UPYUN ppt 架构
  2. OpenResty Practical Experience ppt 使用例子
  3. OpenResty/Lua高级编程技巧
  4. lua & ngx_lua 的介绍与应用 ppt 从lua 和 nginx两方面将的,架构变迁
  5. Nginx lua 日本人的ppt,主要讲了nginx处理请求的几个阶段

视频

iresty openresty 视频讲座集合

坚持原创技术分享,您的支持将鼓励我继续创作!
0%