acl 不支持redis 集群 事务操作

切记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;
}

这里写图片描述

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

猜你喜欢

转载自blog.csdn.net/CAir2/article/details/79037346