resty-redis-cluster icon indicating copy to clipboard operation
resty-redis-cluster copied to clipboard

压力测试下或者并发下的问题

Open manpeter opened this issue 5 years ago • 12 comments

当我用ab进行压力测试的时候就会出现如下错误,不清楚问题出在哪里,是因为加锁的原因吗,应该怎么解决

ab -n 1000 -c 100 -k http://127.0.0.1:8002/product?id=15

下面是代码测试就会报错 local config = { name = "testCluster", --rediscluster name serv_list = {{ ip = "xx.xx.xx.xx", port = 6383 } }, keepalive_timeout = 1000, --redis connection pool idle timeout keepalive_cons = 10, --redis connection pool size connection_timout = 1000, --timeout while connecting max_redirection = 5 --maximum retry attempts for redirection } local redis_cluster = require "rediscluster" red_c,err = redis_cluster:new(config) if not red_c then ngx.say(ngx.ERR, "connect to redis error : ", err) return end local content,err =red_c:get('shop_info_'..id)

image

manpeter avatar Jan 15 '19 13:01 manpeter

你好,能把你的err 完整贴上来吗?

steve0511 avatar Jan 15 '19 14:01 steve0511

stack traceback: coroutine 0: /lua-packge/resty-redis-cluster-master/lib/rediscluster.lua: in function 'handleCommandWithRetry' /lua-packge/resty-redis-cluster-master/lib/rediscluster.lua:406: in function 'get' /nginx-test/lua-project/test-template.lua:125: in function </nginx-test/lua-project/test-template.lua:1>, client: 172.30.0.1, server: xxxxx.com, request: "GET /product?id=15 HTTP/1.0", host: "127.0.0.1:8002" 2019/01/16 12:50:15 [error] 7#0: *16631 [lua] rediscluster.lua:159: init_slots(): failed to acquire the lock in initialization slot cache: timeout, client: 172.30.0.1, server: xxxxx.com, request: "GET /product?id=15 HTTP/1.0", host: "127.0.0.1:8002" 2019/01/16 12:50:15 [error] 7#0: *16631 lua entry thread aborted: runtime error: /lua-packge/resty-redis-cluster-master/lib/rediscluster.lua:290: attempt to index local 'slots' (a nil value)

manpeter avatar Jan 16 '19 04:01 manpeter

image

使用jmeter测试的,4核8G,1000并发下,平均63ms:jmeter -n -t gateway.jmx -l test.result -e -o ./weblog/

local config = {
    name = "testCluster",                   --rediscluster name
    serv_list = {                           --redis cluster node list(host and port),
        { ip = "172.16.0.165", port = 7000 },
        { ip = "172.16.0.165", port = 7001 },
        { ip = "172.16.0.165", port = 7002 },
        { ip = "172.16.0.75", port = 7003 },
        { ip = "172.16.0.75", port = 7004 },
        { ip = "172.16.0.75", port = 7005 }
    },
    keepalive_timeout = 60000,              --redis connection pool idle timeout
    keepalive_cons = 1000,                  --redis connection pool size
    connection_timout = 1000,               --timeout while connecting
    max_redirection = 5,                    --maximum retry attempts for redirection,
    auth = "xxxx"                       --set password while setting auth
}

local redis_cluster = require "rediscluster"
local red_c = redis_cluster:new(config)

local redisvalue = string.format("%s%s","xxxxxxxxxxxxxxxxx:", ngx.req.get_headers()["token"])
--ngx.log(ngx.INFO, "value: ", redisvalue);

local v, err = red_c:hget(redisvalue,"creationTime")


--ngx.log(ngx.ERR, "v: ", v)

if err then
    ngx.log(ngx.ERR, "err: ", err)

else
    local m = ngx.re.match("null", v)

    if m then
       ngx.status = ngx.HTTP_UNAUTHORIZED;
  --  ngx.log(ngx.ERR, "err: ", err)
    else
       ngx.status = ngx.HTTP_OK;
  --         -- ngx.say(v)
    end
  --
end

我是先判断err,然后再判断返回结果~

感谢作者 @steve0511

asukaliy1 avatar Jan 16 '19 08:01 asukaliy1

@asukaliy1 你是把他放到init_worker_lua这个阶段处理就初始化了连接池吗,还是怎么做的,请指教

manpeter avatar Jan 17 '19 11:01 manpeter

@asukaliy1 你是把他放到init_worker_lua这个阶段处理就初始化了连接池吗,还是怎么做的,请指教

不管你写哪儿,只会初始化一次的,后来的连接处理时都是引用

1、please compile and generate redis_slot.so from redis_slot.c (can done by gcc)

2、please add redis_slot.so and rediscluster.lua at lualib, Also please add library:lua-resty-redis and lua-resty-lock nginx.conf like:

lua_package_path "/path/lualib/?.lua;"; lua_package_cpath "/path/lualib/?.so;";

3、nginx.conf add config:

lua_shared_dict redis_cluster_slot_locks 100k;

这里的三个步骤你都实现了么

asukaliy1 avatar Jan 17 '19 13:01 asukaliy1

@asukaliy1 实现了,我还以为nginx多进程需要在工作进程初始化,意思是整个工作进程当中都会引用相同的连接池吗,比如我在content_lua 阶段连接了,又在另外一个阶段又再次做了连接,也是复用相同的连接池吗?

manpeter avatar Jan 17 '19 14:01 manpeter

rediscluster是个模块(table),require之后,缓存在 package.loaded 这个全局表中(这个表是注册在 Lua registry 里,而 Lua registry 是 VM 级别唯一的,共享的); 每个nginx worker(工作进程)创建一个Lua VM,worker内所有协程共享VM; 因此你之后的require之后,其实只是获取一个引用;

具体可以参考并发请求的变量问题

asukaliy1 avatar Jan 18 '19 00:01 asukaliy1

而且rediscluster底层依然是使用ngx_lua's cosocket API的,而tcpsock:connect是不支持在init_worker_lua环境中使用的~ ngx.socket.tcp说明

asukaliy1 avatar Jan 18 '19 00:01 asukaliy1

而且rediscluster底层依然是使用ngx_lua的cosocket API的,而tcpsock:connect是不支持在init_worker_lua环境中使用的~ ngx.socket.tcp说明

那么解决问题的方法是什么呢?

jesse007007 avatar Mar 22 '19 09:03 jesse007007

请问支持主从模式么?这个库, 一台master,一台slaver

sixtool avatar Mar 28 '19 09:03 sixtool

这个lib只支持rediscluster, master/slave还是用https://github.com/openresty/lua-resty-redis

steve0511 avatar Apr 05 '19 00:04 steve0511

当我用ab进行压力测试的时候就会出现如下错误,不清楚问题出在哪里,是因为加锁的原因吗,应该怎么解决

ab -n 1000 -c 100 -k http://127.0.0.1:8002/product?id=15

下面是代码测试就会报错 local config = { name = "testCluster", --rediscluster name serv_list = {{ ip = "xx.xx.xx.xx", port = 6383 } }, keepalive_timeout = 1000, --redis connection pool idle timeout keepalive_cons = 10, --redis connection pool size connection_timout = 1000, --timeout while connecting max_redirection = 5 --maximum retry attempts for redirection } local redis_cluster = require "rediscluster" red_c,err = redis_cluster:new(config) if not red_c then ngx.say(ngx.ERR, "connect to redis error : ", err) return end local content,err =red_c:get('shop_info_'..id)

image

老哥,我也压测碰到这个问题。量小美报错,并发价大就timeout,请问你已经解决了嘛?

liangwangkai avatar Aug 26 '19 11:08 liangwangkai