acl 不支援redis 叢集 事務操作
阿新 • • 發佈:2018-12-25
切記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庫並不支援事務操作,如果使用事務操作將放生各種問題。