说明:
1、require是 lua 里面引入其他库的关键字。这里引入的 cjson。
2、当我们要读取 http里的post数据的时候,就需要使用ngx.req.read_body()。该API同步读取客户端请求主体而不阻塞Nginx事件循环。
3、 用于获取post请求数据。
4、ngx.var.remote_var实际是获取的nginx里的变量remote_var。也就是说,ngx.var.xxx实际是获取的nginx里的变量xxx。例如:
nginx变量详见:[Alphabetical index of variables}()。 ngx_lua ngx.var API详见:。
5、 用于读取nginx的header参数。返回的是lua table。
6、用于 base64字符串解码。对应的编码API是 ngx.encode_base64()。
连接数据库
连接数据库我们需要使用到ngx_lua的第三方库:
lua-resty-redis library based on ngx_lua cosocket.
lua-resty-mysql library based on ngx_lua cosocket.
这两个库都是基于cosocket实现的,特点是异步非阻塞。代码风格是同步的写法。更多第三方库详见: 。
连接 MySQL
lua代码:
nginx/conf/lua/test_mysql.lua
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.say("failed to instantiate mysql: ", err)
return
end
db:set_timeout(1000) -- 1 sec
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "ngx_test",
user = "ngx_test",
password = "ngx_test",
charset = "utf8",
max_packet_size = 1024 * 1024,
}
if not ok then
ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate)
return
end
-- insert
res, err, errcode, sqlstate =
db:query("insert into cats (name) "
.. "values (\'Bob\'),(\'\'),(null)")
if not res then
ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
return
end
ngx.say(res.affected_rows, " rows inserted into table cats ",
"(last insert id: ", res.insert_id, ")")
-- run a select query, expected about 10 rows in the result set
res, err, errcode, sqlstate =
db:query("select * from cats order by id asc", 10)
if not res then
ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
return
end
local cjson = require "cjson"
ngx.say("result: ", cjson.encode(res))
-- close connection
local ok, err = db:close()
if not ok then
ngx.say("failed to close: ", err)
return
end
修改 nginx.conf ,新增:
location /test_mysql {
content_by_lua_file conf/lua/test_mysql.lua;
}
由于修改了 nginx.conf ,需要 reload OpenResty 服务。然后,我们访问服务:
$ :8080/test_mysql
连接 Redis
lua代码:
nginx/conf/lua/test_redis.lua
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 1 sec
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ok, err = red:set("dog", "an animal")
if not ok then
ngx.say("failed to set dog: ", err)
return
end
ngx.say("set result: ", ok)
local res, err = red:get("dog")
if not res then
ngx.say("failed to get dog: ", err)
return
end
if res == ngx.null then
ngx.say("dog not found.")
return
end
ngx.say("dog: ", res)
-- close the connection right away
local ok, err = red:close()
if not ok then
ngx.say("failed to close: ", err)
return
end
修改 nginx.conf ,新增:
location /test_redis {
content_by_lua_file conf/lua/test_redis.lua;
}
由于修改了 nginx.conf ,需要 reload OpenResty 服务。然后,我们访问服务:
$ :8080/test_redis
更多参考:
redis 接口的二次封装(简化建连、拆连等细节) · OpenResty最佳实践
OpenResty 缓存
使用 Lua shared dict
使用的话首先需要在 nginx.conf 加上一句:
lua_shared_dict my_cache 128m;
这个my_cache就是申请 Lua shared dict 缓存, 下面示例里会用到。
这个缓存是 Nginx 所有 worker 之间共享的,内部使用的 LRU 算法(最近最少使用)来判断缓存是否在内存占满时被清除。
function get_from_cache(key)
local cache_ngx = ngx.shared.my_cache
local value = cache_ngx:get(key)
return value
end
function set_to_cache(key, value, exptime)
if not exptime then
exptime = 0
end
local cache_ngx = ngx.shared.my_cache
local succ, err, forcible = cache_ngx:set(key, value, exptime)
return succ
end
更多支持的命令详见: 。
使用 Lua LRU cache
这个 cache 是 worker 级别的,不会在 Nginx wokers 之间共享。并且,它是预先分配好 key 的数量,而 shared dict 需要自己用 key 和 value 的大小和数量,来估算需要把内存设置为多少。
官方示例:
myapp.lua
local _M = {}
-- alternatively: local lrucache = require "resty.lrucache.pureffi"
local lrucache = require "resty.lrucache"
-- we need to initialize the cache on the lua module level so that
-- it can be shared by all the requests served by each nginx worker process:
local c, err = lrucache.new(200) -- allow up to 200 items in the cache
if not c then
return error("failed to create the cache: " .. (err or "unknown"))
end
function _M.go()
c:set("dog", 32)
c:set("cat", 56)
ngx.say("dog: ", c:get("dog"))
ngx.say("cat: ", c:get("cat"))
c:set("dog", { age = 10 }, 0.1) -- expire in 0.1 sec
c:delete("dog")
c:flush_all() -- flush all the cached data
end
return _M
nginx.conf
http {
lua_package_path "/path/to/lua-resty-lrucache/lib/?.lua;;";
server {
listen 8080;
location = /t {
content_by_lua '
require("myapp").go()
';
}
}
}
更多支持的命令详见:https://github.com/openresty/lua-resty-lrucache 。
那么这两个缓存 如何选择 ?