OpenResty连接Redis
来源:互联网 发布:临沂广电网络客服电话 编辑:程序博客网 时间:2024/06/06 08:39
通常来说,对于OpenResty的应用多数都会用到Redis,用以减少回源次数,从而加速网站。话不多说,先上一个demo
redis_iresty.lua
普通命令
第一个调用的是new(opts),入参是一个table,可以设置两个值,timeout和db索引值。(其他相关连接参数在工具内部,实际使用时可以抽出来配置文件)如timeout不设置,则默认超时为1s。
在new的时候返回的是iresty对象本身,因此new上面对基本上所有的redis命令进行了重写。并最终由do_command方法去调用resty.redis的方法,实现了与原生resty.redis相同的API。
还有一点需要提及的就是,上述API的封装是用到连接池的(虽然API中不能明显看出)。在new的时候并没有到连接池中获取连接,而是在具体的命令调用时(do_command方法中connect_mod)才去到cosocket连接池中去获取TCP连接的。cosocket中的连接池是以IP和端口号作为连接池的KEY,redis:connect(ip, port)才可以获取对应的TCP连接。
批量操作
对于批量操作,上述工具里面主要包含两个接口:init_pipeline()和commit_pipeline()。当批量命令开始时,执行init_pipeline(),此时会初始化一个命令缓冲区_reqs,用以存储待执行的批量命令。最后调用_M:set_keepalive_mod中的redis:set_keepalive(60000, 1000)方法,用以释放连接到池中。若此时没有以此IP和端口号为KEY的连接池,则会创建一个大小为1000的连接池,最大存活时间为60s。
订阅服务
对于订阅服务,调用代码请参见如下:
链接:http://moguhu.com/article/detail?articleId=20
redis_iresty.lua
-- file name: resty/redis_iresty.lualocal 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 {} endendlocal _M = new_tab(0, 155)_M._VERSION = '0.01'local commands = { "append", "bgsave", "blpop", "brpoplpush", "auth", "bitcount", "brpop", "client", "bgrewriteaof", "bitop", "config", "dbsize", "debug", "decr", "del", "discard", "echo", "eval", "exec", "expire", "expireat", "flushdb", "get", "getrange", "getset", "hexists", "hget", "hincrby", "hincrbyfloat", "hlen", "hmget", "hset", "hsetnx", "incrby", "keys", "lastsave", "llen", "lpushx", "lset", "migrate", "monitor", "msetnx", "persist", "ping", "pttl", "publish", "quit", "randomkey", "restore", "rpop", "rpushx", "scan", "sdiff", "select", "setex", "shutdown", "sismember", "smembers", "spop", "sscan", "strlen", "sunionstore", "ttl", "type", "watch", "zcount", "zrange", "zrem", "zrevrange", "zscan", "zscore", "hmset", "hvals", "incrbyfloat", "lindex", "lpop", "lrange", "ltrim", "move", "multi", "pexpire", "psetex", --[[ "punsubscribe", ]] "rename", "info", "linsert", "lpush", "lrem", "mget", "mset", "object", "pexpireat", "psubscribe", "pubsub", "renamenx", "rpush", "save", "script", "setbit", "setrange", "sinterstore", "slowlog", "sort", "srem", "sunion", "time", "rpoplpush", "sadd", "scard", "sdiffstore", "set", "setnx", "sinter", "slaveof", "smove", "srandmember", --[[ "subscribe", ]] "sync", --[[ "unsubscribe", ]] "zunionstore", "evalsha", "decrby", "dump", "exists", "flushall", "getbit", "hdel", "hgetall", "hkeys", "hscan", "incr", "zadd", "zincrby", "zrangebyscore","zrank", "zremrangebyrank", "zremrangebyscore", "zrevrangebyscore", "zrevrank", "unwatch", "zcard", "zinterstore" }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 falseend-- change connect address as you needfunction _M.connect_mod( self, redis ) redis:set_timeout(self.timeout) return redis:connect("127.0.0.1", 6379)endfunction _M.set_keepalive_mod( redis ) -- put it into the connection pool of size 100, with 60 seconds max idle time return redis:set_keepalive(60000, 1000)endfunction _M.init_pipeline( self ) self._reqs = {}endfunction _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) for i,value in ipairs(results) do if is_redis_null(value) then results[i] = nil end end return results, errendfunction _M.subscribe( self, channel ) 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 local res, err = redis:subscribe(channel) if not res then return nil, err end local function do_read_func ( do_read ) if do_read == nil or do_read == true then res, err = redis:read_reply() if not res then return nil, err end return res end redis:unsubscribe(channel) self.set_keepalive_mod(redis) return end return do_read_funcendlocal 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 local fun = redis[cmd] local result, err = fun(redis, ...) if not result or err then return nil, err end if is_redis_null(result) then result = nil end self.set_keepalive_mod(redis) return result, errendfor i = 1, #commands do local cmd = commands[i] _M[cmd] = function (self, ...) return do_command(self, cmd, ...) endend function _M.new(self, opts) opts = opts or {} local timeout = (opts.timeout and opts.timeout * 1000) or 1000 --1s local db_index= opts.db_index or 0 return setmetatable({ timeout = timeout, db_index = db_index, _reqs = nil }, mt)endreturn _M上述代码片段摘自OpenResty 最佳实践,上面的模块是对resty.redis的包装。其中抽象了连接创建、认证及释放的过程,并且对外统一为池化操作。下面为一个调用的demo:
local redis = require "resty.redis_iresty"local red = redis:new()local ok, err = red:set("dog", "an animal")if not ok then ngx.say("failed to set dog: ", err)return endngx.say("set result: ", ok)这里调用的代码很简单,就不再多说了,下面说一下上面resty_iredis.lua的内容。
普通命令
第一个调用的是new(opts),入参是一个table,可以设置两个值,timeout和db索引值。(其他相关连接参数在工具内部,实际使用时可以抽出来配置文件)如timeout不设置,则默认超时为1s。
在new的时候返回的是iresty对象本身,因此new上面对基本上所有的redis命令进行了重写。并最终由do_command方法去调用resty.redis的方法,实现了与原生resty.redis相同的API。
还有一点需要提及的就是,上述API的封装是用到连接池的(虽然API中不能明显看出)。在new的时候并没有到连接池中获取连接,而是在具体的命令调用时(do_command方法中connect_mod)才去到cosocket连接池中去获取TCP连接的。cosocket中的连接池是以IP和端口号作为连接池的KEY,redis:connect(ip, port)才可以获取对应的TCP连接。
批量操作
对于批量操作,上述工具里面主要包含两个接口:init_pipeline()和commit_pipeline()。当批量命令开始时,执行init_pipeline(),此时会初始化一个命令缓冲区_reqs,用以存储待执行的批量命令。最后调用_M:set_keepalive_mod中的redis:set_keepalive(60000, 1000)方法,用以释放连接到池中。若此时没有以此IP和端口号为KEY的连接池,则会创建一个大小为1000的连接池,最大存活时间为60s。
订阅服务
对于订阅服务,调用代码请参见如下:
local red = redis:new({timeout=1000})local func = red:subscribe( "channel" )if not func then return nilendwhile true do local res, err = func() if err then func(false) end... ...endreturn cbfunc
链接:http://moguhu.com/article/detail?articleId=20
阅读全文
1 0
- OpenResty连接Redis
- openresty-redis
- Openresty最佳案例 | 第7篇: 模块开发、OpenResty连接Redis
- 安装openresty+redis+lua
- 关于OpenResty的redis
- nginx+lua+redis(openresty)配置
- Openresty + MySQL + Redis 安装篇
- openresty+websocket+redis simple chat
- openresty 限流 (redis+lua) 备忘
- openresty操作redis订阅者
- Openresty最佳案例 | 第6篇:OpenResty连接Mysql
- openresty--基于redis实现一个动态路由
- Linux下openresty+redis 的权限控制
- openresty
- OpenResty
- openresty
- openresty
- openresty
- 部署lftp服务器、建立ftp虚拟用户
- Play framework自定义扩展JavaExtensions
- VS2015+OpenCV-2.4.10配置AR(增强现实)开发环境
- 第14期《成长之路》2017年8月刊
- 进程通信之共享内存
- OpenResty连接Redis
- 【JavaWeb】JSP运行原理和九大隐式对象
- codeforces837E Vasya's Function
- 回调函数/Callback(维基百科)
- 异常积累(一)
- 全排列java实现
- CSDN博客开盘首文
- ajax的弊端 爬虫难以爬取 搜索引擎不易收录 解决办法 pajax hijax
- SJA1000的调试经历【转】