OpenResty高并发最佳实践--Redis操作

前言

使用到了OpenResty,很核心的目的是为了解决高并发的问题,为了不让数据库成为高并发的瓶颈,那么操作redis就变的不可避免了,下面介绍OpenResty操作redis的过程

准备

不了解OpenResty的可以参考以下文章
OpenResty(Nginx+Lua)高并发最佳实践
Window下基于ZeroBrane Studio开发调试OpenResty

代码走起
  • redis连接池(工具类)
    在OpenResty的lualib目录下创建testcode文件夹,用于放置我们的测试lua脚本,并在文件夹下创建redis_factory.lua,如下图:

    将以下代码拷贝至该文件(不需要做任何修改):

    local redis_factory = function(h)
        
        local h           = h
    
        h.redis           = require('resty.redis')
        h.cosocket_pool   = {max_idel = 10000, size = 10000}
    
        h.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",
            -- resty redis private command
            "set_keepalive",     "init_pipeline",     "commit_pipeline",      
            "array_to_hash",     "add_commands",      "get_reused_times",
        }
    
        -- connect
        -- @param table connect_info, e.g { host="127.0.0.1", port=6379, pass="", timeout=1000, database=0}
        -- @return boolean result
        -- @return userdata redis_instance
        h.connect = function(connect_info)
            local redis_instance = h.redis:new()
            redis_instance:set_timeout(connect_info.timeout)
            if not redis_instance:connect(connect_info.host, connect_info.port) then 
                return false, nil
            end
            if connect_info.pass ~= '' then
                redis_instance:auth(connect_info.pass)
            end
            redis_instance:select(connect_info.database)
            return true, redis_instance
        end
    
        -- spawn_client
        -- @param table h, include config info
        -- @param string name, redis config name
        -- @return table redis_client
        h.spawn_client = function(h, name)
    
            local self = {}
            
            self.name           = ""
            self.redis_instance = nil
            self.connect        = nil
            self.connect_info   = {
                host = "",   port = 0,    pass = "", 
                timeout = 0, database = 0
            }
    
            -- construct
            self.construct = function(_, h, name)
                -- set info
                self.name         = name
                self.connect      = h.connect
                self.connect_info = h[name]
                -- gen redis proxy client
                for _, v in pairs(h.commands) do
                    self[v] = function(self, ...)
                        -- instance test and reconnect  
                        if (type(self.redis_instance) == 'userdata: NULL' or type(self.redis_instance) == 'nil') then
                            local ok
                            ok, self.redis_instance = self.connect(self.connect_info)
                            if not ok then return false end
                        end
                        -- get data
                        local vas = { ... }
                        return self.redis_instance[v](self.redis_instance, ...)
                    end
                end
                return true
            end
    
            -- do construct
            self:construct(h, name) 
    
            return self
        end     
    
    
    
        local self = {}
    
        self.pool  = {} -- redis client name pool
    
        -- construct
        -- you can put your own construct code here.
        self.construct = function()
            return
        end
    
        -- spawn
        -- @param string name, redis database serial name
        -- @return boolean result
        -- @return userdata redis
        self.spawn = function(_, name)
            if self.pool[name] == nil then
                ngx.ctx[name] = h.spawn_client(h, name) 
                self.pool[name] = true
                return true, ngx.ctx[name]
            else
                return true, ngx.ctx[name]
            end
        end
    
        -- destruct
        -- @return boolean allok, set_keepalive result
        self.destruct = function()
            local allok = true
            for name, _ in pairs(self.pool) do
                local ok, msg = ngx.ctx[name].redis_instance:set_keepalive(
                    h.cosocket_pool.max_idel, h.cosocket_pool.size
                )
                if not ok then allok = false end 
            end
            return allok
        end
    
        -- do construct
        self.construct() 
            
        return self
    end
    
    
    return redis_factory
    
    
  • 配置文件
    同级目录下创建config_constant.lua,用于防止redis或者其他的公共配置文件

    将以下代码拷贝至该文件,具体配置数据请根据自己的redis数据库的情况修改

    config = {}
    
    config.redisConfig = {
        redis_a = { -- your connection name 
            --ip
            host = '127.0.0.1',
            --端口
            port = 6379,
            --密码
            pass = '123456789',
            --超时时间,如果是测试环境debug的话,这个值可以给长一点;如果是正式环境,可以设置为200
            timeout = 120000,
            --redis的库
            database = 0,
        },
    --    redis_b = {
    --    --        host = '127.0.0.1',
    --    --        port = 6379,
    --    --       pass = '',
    --    --        timeout = 200,
    --    --        database = 0,
    --    --    },
        }
    return config
    
测试
  • 编写测试脚本
    前端传递需要查询的key,将key的值取出来并返回给前端
    在testcode文件下创建redistest.lua并拷贝一下至该文件

    --平台公共的配置文件常量
    local config = require "testcode.config_constant"
    --redis连接池工厂
    local redis_factory = require('testcode.redis_factory')(config.redisConfig) -- import config when construct
    --获取redis的连接实例
    local ok, redis_a = redis_factory:spawn('redis_a')
    
    --用于接收前端数据的对象
    local args=nil
    --获取前端的请求方式 并获取传递的参数   
    local request_method = ngx.var.request_method
    --判断是get请求还是post请求并分别拿出相应的数据
    if"GET" == request_method then
            args = ngx.req.get_uri_args()
    elseif "POST" == request_method then
            ngx.req.read_body()
            args = ngx.req.get_post_args()
            --兼容请求使用post请求,但是传参以get方式传造成的无法获取到数据的bug
            if (args == nil or args.data == null) then
                    args = ngx.req.get_uri_args()
            end
    end
    
    --获取前端传递的key
    local key = args.key
    
    --在redis中获取key对应的值
    local va = redis_a:get(key)
    
    --响应前端
    ngx.say('{"key":"'..key..'","va":"'..va..'"}')
    
  • 配置OpenResty下Nginx的Lua文件关联
    在nginx.con中的80配置下添加如下配置

    		location /redis
    		{
    			default_type text/html;
    			#这里的lua文件的路径为绝对路径,请根据自己安装的实际路径填写
    			#记得斜杠是/这个,从window中拷贝出来的是\这样,这样是有问题的,务必注意
    			content_by_lua_file F:/DATA/software/other/openresty-1.13.6.2-win32/lualib/testcode/redistest.lua;
    		}
    

  • 重启OpenResty的Nginx
    nginx -s reload

  • 准备redis的测试数据

  • 测试
    浏览器请求:http://127.0.0.1/redis?key=a 出现以下结果,则正常测试成功


到此,Lua操作redis完成!!!

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一行Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值