Openresty+Lua Redis連接池實(shí)現(xiàn)

Talk is cheap. Show me the code.

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
    --釋放連接(連接池實(shí)現(xiàn))
    local pool_max_idle_time = self.pool_max_idle_time --最大空閑時(shí)間 毫秒
    local pool_size = self.pool_size --連接池大小

    local ok, err = redis:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx.log(ngx.ERR, "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.log(ngx.ERR, "connect to redis error : ", err)
        return self:close_redis(redis)
    end

    if self.password then ----密碼認(rèn)證
        local count, err = redis:get_reused_times()
        if 0 == count then ----新建連接,需要認(rèn)證密碼
            ok, err = redis:auth(self.password)
            if not ok then
                ngx.log(ngx.ERR, "failed to auth: ", err)
                return
            end
        elseif err then  ----從連接池中獲取連接奏窑,無(wú)需再次認(rèn)證密碼
            ngx.log(ngx.ERR, "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_pool'):new()
-- 初始化連接池
redis:init_pipeline()

-- 寫入數(shù)據(jù)
redis:rpush("cache_key", 1)
redis:rpush("cache_key", 2)
redis:rpush("cache_key", 3)
-- 其他命令可以照貓畫虎
-- 命令從官網(wǎng) https://redis.io/ 自行查詢,參數(shù)跟在后邊即可

-- 提交管道批量操作
local results, err = redis:commit_pipeline()
-- 沒(méi)有返回結(jié)果時(shí)墨叛,請(qǐng)檢查是否有錯(cuò)誤發(fā)生
if not results then
    ngx.log(ngx.ERR, "cache failed, ", err)
else
    -- 這里獲取結(jié)果,下標(biāo)從 1 開(kāi)始滓技,依次獲取到結(jié)果
    ngx.say("cache item 1 = ", results[1])
    ngx.say("cache item 2 = ", results[2])
    ngx.say("cache item 3 = ", results[3])
end

輸出:

cache item 1 = 1
cache item 2 = 2
cache item 3 = 3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末令漂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子荚孵,更是在濱河造成了極大的恐慌纬朝,老刑警劉巖共苛,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異澄峰,居然都是意外死亡辟犀,警方通過(guò)查閱死者的電腦和手機(jī)堂竟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)席楚,“玉大人酣胀,你說(shuō)我怎么就攤上這事娶聘。” “怎么了铆农?”我有些...
    開(kāi)封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵墩剖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我郊霎,道長(zhǎng),這世上最難降的妖魔是什么书劝? 我笑而不...
    開(kāi)封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任购对,我火速辦了婚禮陶因,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘楷扬。我一直安慰自己烘苹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著捆探,像睡著了一般站粟。 火紅的嫁衣襯著肌膚如雪奴烙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天揩环,我揣著相機(jī)與錄音丰滑,去河邊找鬼倒庵。 笑死炫刷,一個(gè)胖子當(dāng)著我的面吹牛浑玛,可吹牛的內(nèi)容都是我干的噩咪。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拘央,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼灰伟!你這毒婦竟也來(lái)了栏账?” 一聲冷哼從身側(cè)響起栈源,我...
    開(kāi)封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤甚垦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后闭翩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迄埃,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侄非,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了者疤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宛渐。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窥翩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出笔时,到底是詐尸還是另有隱情允耿,我是刑警寧澤扒怖,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布盗痒,位于F島的核電站,受9級(jí)特大地震影響骡楼,放射性物質(zhì)發(fā)生泄漏稽鞭。R本人自食惡果不足惜朦蕴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一涉茧、第九天 我趴在偏房一處隱蔽的房頂上張望琴拧。 院中可真熱鬧蚓胸,春花似錦沛膳、人聲如沸汛聚。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)风罩。三九已至超升,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乾闰,已是汗流浹背盈滴。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工涯肩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雹熬。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓宽菜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親竿报。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铅乡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容