切记ACL不支持Redis 集群事务,并且千万不要使用事务,否则各种连接数据错误问题,如果一定要使用请单独连接连接,在该连接上使用事务
首先简单描述一下我出现的问题:使用的acl的redis连接池,然后模块1从连接池里面取连接,使用redis事务更新数据,模块2从连接池里面取连接,获取redis的数据。但是发现模块2在使用redis get数据的时候有时候会返回”+QUEUED”即:REDIS_RESULT_STATUS,”+QUEUED”是使用事务才应该发生的事情,为什么会出现在get接口上面呢?get接口明明没有使用事务啊?只有模块一才会使用事务。
“+QUEUED”了解redis协议:​​​redis协议​​​
“Redis集群事务’+QUEUED’现象”:​​​Redis集群事务​​​
通过上述代码,感觉问题应该出现在acl的redis连接池,然后调试代码发现 redis_command.cpp的

const redis_result* redis_command::run(redis_client_cluster* cluster,
size_t nchild, int* timeout /* = NULL */)
{
省掉上半部分
.................................
// 如果出错信息为重定向指令,则执行重定向过程
if (EQ(ptr, "MOVED"))
{
// 将旧连接对象归还给连接池对象
conn->get_pool()->put(conn, true);

const char* addr = get_addr(ptr);
if (addr == NULL)
{
logger_warn("MOVED invalid, ptr: %s", ptr);
return result_;
}

conn = redirect(cluster, addr);

if (conn == NULL)
{
logger_error("redirect NULL, addr: %s", addr);
return result_;
}

ptr = conn->get_pool()->get_addr();

set_client_addr(ptr);

if (n >= 2 && redirect_sleep_ > 0
&& strcmp(ptr, addr) != 0)
{
logger("redirect %d, curr %s, waiting %s ...",
n, ptr, addr);
acl_doze(redirect_sleep_);
}

last_moved = true;

// 需要保存哈希槽值
clear(true);
}
...........................省略下半部分.......................................
}

上述代码发现:如果发生重定向则会redirect取出或者创建重定向的连接来执行该指令,从而导致原本执行事务的连接被替换为非事务连接,而被标记为事务的连接则被放入连接池,导致该事务连接上以后从连接池上取出来使用的时候,所有操作都被默认为事务操作然后返回+QUEUED。

然后继续跟踪acl事务操作接口发现:

bool redis_transaction::multi()
{
cmds_.clear();

const char* argv[1];
size_t lens[1];

argv[0] = "MULTI";
lens[0] = sizeof("MULTI") - 1;

build_request(1, argv, lens);
return check_status();
}

bool redis_transaction::run_cmd(const char* cmd,
const std::vector<string>& args)
{
build(cmd, NULL, args);
if (check_status("QUEUED") == false)
return false;

cmds_.push_back(cmd);
return true;
}

bool redis_transaction::exec()
{
const char* argv[1];
size_t lens[1];

argv[0] = "EXEC";
lens[0] = sizeof("EXEC") - 1;

build_request(1, argv, lens);
const redis_result* result = run();
if(result == NULL || result->get_type() != REDIS_RESULT_ARRAY)
return false;

size_t size = result->get_size();
if (size != cmds_.size())
return false;
return true;
}

acl 不支持redis 集群 事务操作_连接池

acl 不支持redis 集群 事务操作_redis_02


redis事务操作并没有计算槽值,通过peek()代码发现,事务的指令连接都是在连接池里面轮询取连接池里面的连接的,所以redis事务操作前后并不保证在同一个连接上。因此综上所述redis 的acl库并不支持事务操作,如果使用事务操作将放生各种问题。