ngx_lua开发往往需要与Redis做交互。以下有两种与redis的交互方式。
使用OpenResty中的lua-resty-redis 这个模块操作 Redis。
对 lua-resty-redis进行了二次封装,封装了开箱即用的连接池,每次 Redis 使用完毕,自动释放 Redis 连接到连接池供其他请求复用。
封装了针对hash/set数据类型的操作方法。
redis-config.lua
local _M = {
redis={ip="192.168.0.12",port="6379",database=1,timeout=10000,max_idle_time=60000,pool_size = 100,auth="xxx"}
}
return _M
redis-utils.lua
local _M = {}
local redis = require("resty.redis")
local red_config = require('redis-config')
local ip = red_config.redis['ip']
local port = red_config.redis['port']
local database = red_config.redis['database']
local auth = red_config.redis['auth']
local timeout = red_config.redis['timeout']
local max_idle_time = red_config.redis['max_idle_time']
local pool_size = red_config.redis['pool_size']
local unpack = unpack or table.unpack
function _M.exec(func)
local red = redis:new()
red:set_timeout(timeout)
local ok, err = red:connect(ip, port)
if not ok then
ngx.say("redis","Cannot connect, host: " .. ip .. ", port: " .. port)
ngx.log(ngx.ERR, "redis","Cannot connect, host: " .. ip .. ", port: " .. port)
return nil, err
end
local count, err = red:get_reused_times()
if 0 == count then
ok, err = red:auth(auth)
if not ok then
ngx.say("failed to auth: ", err)
ngx.log(ngx.ERR,"failed to auth: ", err)
return
end
elseif err then
ngx.say("failed to get reused times: ", err)
ngx.log(ngx.ERR,"failed to get reused times: ", err)
return
end
ngx.say("get reused times: ", count)
ngx.log(ngx.WARN,"get reused times: ", count)
red:select(database)
local res, err = func(red)
if res then
local ok, err1 = red:set_keepalive(max_idle_time, pool_size)
if not ok then
red:close()
end
end
return res, err
end
--hash
function _M.hkeys(key, ...)
local array={}
for i = 1, select('#', ...) do
array[i]=select(i, ...)
ngx.say(array[i])
ngx.log(ngx.WARN,array[i])
end
local res, err = _M.exec(
function(red)
return red:hkeys(unpack(array))
end
)
if not res then
return nil
end
if type(res) == "userdata" then
return nil
end
return res
end
function _M.hset(key, ...)
local array={}
for i = 1, select('#', ...) do
array[i]=select(i, ...)
ngx.say(array[i])
ngx.log(ngx.WARN,array[i])
end
local res, err = _M.exec(
function(red)
--red:expire(key, expires)
return red:hset(unpack(array))
end
)
if not res then
return nil
end
if type(res) == "userdata" then
return nil
end
return res
end
function _M.hget(key, ...)
local array={}
for i = 1, select('#', ...) do
array[i]=select(i, ...)
ngx.say(array[i])
ngx.log(ngx.WARN,array[i])
end
local res, err = _M.exec(
function(red)
return red:hget(unpack(array))
end
)
if not res then
return nil
end
if type(res) == "userdata" then
return nil
end
return res
end
--set
function _M.smembers(key, ...)
local array={}
for i = 1, select('#', ...) do
array[i]=select(i, ...)
ngx.say(array[i])
ngx.log(ngx.WARN,array[i])
end
local res, err = _M.exec(
function(red)
return red:smembers(unpack(array))
end
)
if not res then
return nil
end
if type(res) == "userdata" then
return nil
end
return res
end
function _M.sismember(key, ...)
local array={}
for i = 1, select('#', ...) do
array[i]=select(i, ...)
ngx.say(array[i])
ngx.log(ngx.WARN,array[i])
end
local res, err = _M.exec(
function(red)
return red:sismember(unpack(array))
end
)
if not res then
return nil
end
if type(res) == "userdata" then
return nil
end
return res
end
function _M.srem(key, ...)
local array={}
for i = 1, select('#', ...) do
array[i]=select(i, ...)
ngx.say(array[i])
ngx.log(ngx.WARN,array[i])
end
local res, err = _M.exec(
function(red)
return red:srem(unpack(array))
end
)
if not res then
return nil
end
if type(res) == "userdata" then
return nil
end
return res
end
function _M.sadd(key, ...)
local array={}
for i = 1, select('#', ...) do
array[i]=select(i, ...)
ngx.say(array[i])
ngx.log(ngx.WARN,array[i])
end
local res, err = _M.exec(
function(red)
return red:sadd(unpack(array))
end
)
if not res then
return nil
end
if type(res) == "userdata" then
return nil
end
return res
end
return _M
由于在【init_by_lua_file】初始化全局变量阶段,lua-resty-redis还未被加载,因此需要通过封装shell命令行访问redis获得初始化数据。
redis-config.lua
local _M = {
redis={ip="192.168.0.12",port="6379",database=1,timeout=10000,max_idle_time=60000,pool_size = 100,auth="xxx"}
}
return _M
redis-utils-cmd.lua
local _M = {}
local red_config = require('redis-config')
local ip = red_config.redis['ip']
local port = red_config.redis['port']
local database = red_config.redis['database']
local auth = red_config.redis['auth']
local timeout = red_config.redis['timeout']
local max_idle_time = red_config.redis['max_idle_time']
local pool_size = red_config.redis['pool_size']
local redis_connect = "redis-cli -h "..ip.." -p "..port.." -n "..database.." -a '"..auth.."' --no-auth-warning"
function _M.hkeys_hgets(key)
local upstreams = {}
--local cmd=redis_connect.." hkeys "..key.." | awk '{print $NF}' | awk -F '\"' '{print $2}'"
local cmd=redis_connect.." hkeys "..key.." | awk '{print $NF}'"
local f = io.popen(cmd)
--line = f:read("a")
local line = f:read()
while(line ~= nil and line ~= " ")
do
upstreams[line] = _M.hget(key,line)
--print(line,upstreams[line])
line = f:read()
end
f:close()
return upstreams
end
function _M.hget(key,field)
--local cmd=redis_connect.." hget "..key.." "..field.." | awk -F '\"' 'NR==1{print $2}'"
local cmd=redis_connect.." hget "..key.." "..field
local f = io.popen(cmd)
local line = f:read()
f:close()
return line
end
function _M.smembers(key)
local _table = {}
--local cmd=redis_connect.." smembers "..key.." | awk '{print $NF}' | awk -F '\"' '{print $2}'"
local cmd=redis_connect.." smembers "..key.." | awk '{print $NF}'"
local f = io.popen(cmd)
local line = f:read()
while(line ~= nil and line ~= " ")
do
_table[line] = true
--print(line,_table[line])
line = f:read()
end
f:close()
return _table
end
return _M
--redis = require("redis-utils-cmd")
--t = redis.smembers('usernames')
--for k,v in pairs(t)
--do
-- print(k,v)
--end