1. 程式人生 > >acl 不支援redis 叢集 事務操作

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庫並不支援事務操作,如果使用事務操作將放生各種問題。