openresty开发系列27--openresty中封装redis操作
openresty開發系列27--openresty中封裝redis操作
在關于web+lua+openresty開發中,項目中會大量操作redis,
重復創建連接-->數據操作-->關閉連接(或放到連接池)這個完整的鏈路調用完畢,
甚至還要考慮不同的 return 情況做不同處理,就很快發現代碼中有大量的重復
推薦一個二次封裝的類庫
---------------------------------
# 加入openresty的lib庫目錄
# vim openresty/lualib/resty/redis_iresty.lua
local redis_c = require "resty.redis"
local ok, new_tab = pcall(require, "table.new")
if not ok or type(new_tab) ~= "function" then
??? new_tab = function (narr, nrec) return {} end
end
local _M = new_tab(0, 155)
_M._VERSION = '0.01'
local commands = {
??? "append",??????????? "auth",????????????? "bgrewriteaof",
??? "bgsave",??????????? "bitcount",????????? "bitop",
??? "blpop",???????????? "brpop",
??? "brpoplpush",??????? "client",??????????? "config",
??? "dbsize",
??? "debug",???????????? "decr",????????????? "decrby",
??? "del",?????????????? "discard",?????????? "dump",
??? "echo",
??? "eval",????????????? "exec",????????????? "exists",
??? "expire",??????????? "expireat",????????? "flushall",
??? "flushdb",?????????? "get",?????????????? "getbit",
??? "getrange",????????? "getset",??????????? "hdel",
??? "hexists",?????????? "hget",????????????? "hgetall",
??? "hincrby",?????????? "hincrbyfloat",????? "hkeys",
??? "hlen",
??? "hmget",????????????? "hmset",????? "hscan",
??? "hset",
??? "hsetnx",??????????? "hvals",???????????? "incr",
??? "incrby",??????????? "incrbyfloat",?????? "info",
??? "keys",
??? "lastsave",????????? "lindex",??????????? "linsert",
??? "llen",????????????? "lpop",????????????? "lpush",
??? "lpushx",??????????? "lrange",??????????? "lrem",
??? "lset",????????????? "ltrim",???????????? "mget",
??? "migrate",
??? "monitor",?????????? "move",????????????? "mset",
??? "msetnx",??????????? "multi",???????????? "object",
??? "persist",?????????? "pexpire",?????????? "pexpireat",
??? "ping",????????????? "psetex",??????????? "psubscribe",
??? "pttl",
??? "publish",????? --[[ "punsubscribe", ]]?? "pubsub",
??? "quit",
??? "randomkey",???????? "rename",??????????? "renamenx",
??? "restore",
??? "rpop",????????????? "rpoplpush",???????? "rpush",
??? "rpushx",??????????? "sadd",????????????? "save",
??? "scan",????????????? "scard",???????????? "script",
??? "sdiff",???????????? "sdiffstore",
??? "select",??????????? "set",?????????????? "setbit",
??? "setex",???????????? "setnx",???????????? "setrange",
??? "shutdown",????????? "sinter",??????????? "sinterstore",
??? "sismember",???????? "slaveof",?????????? "slowlog",
??? "smembers",????????? "smove",???????????? "sort",
??? "spop",????????????? "srandmember",?????? "srem",
??? "sscan",
??? "strlen",?????? --[[ "subscribe",? ]]???? "sunion",
??? "sunionstore",?????? "sync",????????????? "time",
??? "ttl",
??? "type",???????? --[[ "unsubscribe", ]]??? "unwatch",
??? "watch",???????????? "zadd",????????????? "zcard",
??? "zcount",??????????? "zincrby",?????????? "zinterstore",
??? "zrange",??????????? "zrangebyscore",???? "zrank",
??? "zrem",????????????? "zremrangebyrank",?? "zremrangebyscore",
??? "zrevrange",???????? "zrevrangebyscore",? "zrevrank",
??? "zscan",
??? "zscore",??????????? "zunionstore",?????? "evalsha"
}
local mt = { __index = _M }
local function is_redis_null( res )
??? if type(res) == "table" then
??????? for k,v in pairs(res) do
??????????? if v ~= ngx.null then
??????????????? return false
??????????? end
??????? end
??????? return true
??? elseif res == ngx.null then
??????? return true
??? elseif res == nil then
??????? return true
??? end
??? return false
end
function _M.close_redis(self, redis) ?
??? if not redis then ?
??????? return ?
??? end ?
??? --釋放連接(連接池實現)
??? local pool_max_idle_time = self.pool_max_idle_time --最大空閑時間 毫秒 ?
??? local pool_size = self.pool_size --連接池大小 ?
?? ?
??? local ok, err = redis:set_keepalive(pool_max_idle_time, pool_size) ?
??? if not ok then ?
??????? ngx.say("set keepalive error : ", err) ?
??? end ?
end ?
-- change connect address as you need
function _M.connect_mod( self, redis )
??? redis:set_timeout(self.timeout)
?? ??? ?
?? ?local ok, err = redis:connect(self.ip, self.port)
?? ?if not ok then ?
?? ??? ?ngx.say("connect to redis error : ", err) ?
?? ??? ?return self:close_redis(redis) ?
?? ?end
?? ?
?? ?if self.password then ----密碼認證
?? ??? ?local count, err = redis:get_reused_times()
?? ??? ?if 0 == count then ----新建連接,需要認證密碼
?? ??? ??? ?ok, err = redis:auth(self.password)
?? ??? ??? ?if not ok then
?? ??? ??? ??? ?ngx.say("failed to auth: ", err)
?? ??? ??? ??? ?return
?? ??? ??? ?end
?? ??? ?elseif err then? ----從連接池中獲取連接,無需再次認證密碼
?? ??? ??? ?ngx.say("failed to get reused times: ", err)
?? ??? ??? ?return
?? ??? ?end
?? ?end
??? return ok,err;
end
function _M.init_pipeline( self )
??? self._reqs = {}
end
function _M.commit_pipeline( self )
??? local reqs = self._reqs
??? if nil == reqs or 0 == #reqs then
??????? return {}, "no pipeline"
??? else
??????? self._reqs = nil
??? end
??? local redis, err = redis_c:new()
??? if not redis then
??????? return nil, err
??? end
??? local ok, err = self:connect_mod(redis)
??? if not ok then
??????? return {}, err
??? end
??? redis:init_pipeline()
??? for _, vals in ipairs(reqs) do
??????? local fun = redis[vals[1]]
??????? table.remove(vals , 1)
??????? fun(redis, unpack(vals))
??? end
??? local results, err = redis:commit_pipeline()
??? if not results or err then
??????? return {}, err
??? end
??? if is_redis_null(results) then
??????? results = {}
??????? ngx.log(ngx.WARN, "is null")
??? end
??? -- table.remove (results , 1)
??? --self.set_keepalive_mod(redis)
?? ?self:close_redis(redis) ?
??? for i,value in ipairs(results) do
??????? if is_redis_null(value) then
??????????? results[i] = nil
??????? end
??? end
??? return results, err
end
local function do_command(self, cmd, ... )
??? if self._reqs then
??????? table.insert(self._reqs, {cmd, ...})
??????? return
??? end
??? local redis, err = redis_c:new()
??? if not redis then
??????? return nil, err
??? end
??? local ok, err = self:connect_mod(redis)
??? if not ok or err then
??????? return nil, err
??? end
?? ?redis:select(self.db_index)
?? ?
??? local fun = redis[cmd]
??? local result, err = fun(redis, ...)
??? if not result or err then
??????? -- ngx.log(ngx.ERR, "pipeline result:", result, " err:", err)
??????? return nil, err
??? end
??? if is_redis_null(result) then
??????? result = nil
??? end
??? --self.set_keepalive_mod(redis)
?? ?self:close_redis(redis) ?
??? return result, err
end
for i = 1, #commands do
??? local cmd = commands[i]
??? _M[cmd] =
??????????? function (self, ...)
??????????????? return do_command(self, cmd, ...)
??????????? end
end
function _M.new(self, opts)
??? opts = opts or {}
??? local timeout = (opts.timeout and opts.timeout * 1000) or 1000
??? local db_index= opts.db_index or 0
?? ?local ip = opts.ip or '127.0.0.1'
?? ?local port = opts.port or 6379
?? ?local password = opts.password
?? ?local pool_max_idle_time = opts.pool_max_idle_time or 60000
?? ?local pool_size = opts.pool_size or 100
??? return setmetatable({
??????????? timeout = timeout,
??????????? db_index = db_index,
?? ??? ??? ?ip = ip,
?? ??? ??? ?port = port,
?? ??? ??? ?password = password,
?? ??? ??? ?pool_max_idle_time = pool_max_idle_time,
?? ??? ??? ?pool_size = pool_size,
??????????? _reqs = nil }, mt)
end
return _M
---------------------------------------
調用案例
local redis = require "resty.redis_iresty"
local opts = {
?? ?ip = "10.11.0.215",
?? ?port = "6379",
?? ?password = "redis123",
?? ?db_index = 1
}
local red = redis:new(opts)
local 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)
---------------------------------------
管道
redis.set
redis.get
red:init_pipeline()
red:set("cat", "Marry")
red:set("horse", "Bob")
red:get("cat")
red:get("horse")
local results, err = red:commit_pipeline()
if not results then
??? ngx.say("failed to commit the pipelined requests: ", err)
??? return
end
for i, res in ipairs(results) do
??? ngx.say(res,"<br/>");
end
在日常的開發中我們不需要重復造輪子,只要這個輪子 穩定,高效就可以直接拿過來用
轉載于:https://www.cnblogs.com/reblue520/p/11434632.html
總結
以上是生活随笔為你收集整理的openresty开发系列27--openresty中封装redis操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openresty开发系列26--ope
- 下一篇: openresty开发系列28--ope