考虑一个前置应用程序,其中每个请求共享相同的Redis连接,我认为这是推荐的方式(?)。
在这种情况下,我相信我会看到一些奇怪的watch multi/exec
行为。具体来说,我希望两个交易中的一个因为乐观锁定失败而失败(即:watch
后卫),但两者似乎都没有发脾气,但导致错误的最终值。
为了说明看下面的设计方案。它在Node中,但我相信这是一般性的。这会并行运行2个进程,这两个进程都会更新计数器。 (它基本上实现了Watch的典型示例,如Redis Docs中所示。
预期结果是第一个进程导致增量为1而第二个进程无法更新并返回null
。相反,结果是两个进程都用1更新计数器。但是一个基于一个陈旧的计数器,所以最后计数器增加1而不是2。
//NOTE: db is a promisified version of node-redis, but that really doesn't matter
var db = Source.app.repos.redis._raw;
Promise.all(_.reduce([1, 2], function(arr, val) {
db.watch("incr");
var p = Promise.resolve()
.then(function() {
return db.get("incr");
})
.then(function(val) { //say 'val' returns '4' for both processes.
console.log(val);
val++;
db.multi();
db.set("incr", val);
return db.exec();
})
.then(function(resultShouldBeNullAtLeastOnce) {
console.log(resultShouldBeNullAtLeastOnce);
return; //explict end
});
arr.push(p);
return arr;
}, [])).then(function() {
console.log("done all");
next(undefined);
})
在拖尾Redis'MONITOR命令时会看到结果交错:
1414491001.635833 [0 127.0.0.1:60979] "watch" "incr"
1414491001.635936 [0 127.0.0.1:60979] "watch" "incr"
1414491001.636225 [0 127.0.0.1:60979] "get" "incr"
1414491001.636242 [0 127.0.0.1:60979] "get" "incr"
1414491001.636533 [0 127.0.0.1:60979] "multi"
1414491001.636723 [0 127.0.0.1:60979] "set" "incr" "5"
1414491001.636737 [0 127.0.0.1:60979] "exec"
1414491001.639660 [0 127.0.0.1:60979] "multi"
1414491001.639691 [0 127.0.0.1:60979] "set" "incr" "5"
1414491001.639704 [0 127.0.0.1:60979] "exec"
这是预期的行为吗?使用多个redis连接会绕过这个问题吗?
答案 0 :(得分:0)
回答我自己的问题:
这是预期的行为。第一个exec
取消了所有属性。因此,第二个multi/exec
没有守卫。
它位于docs,但它相当隐蔽。
解决方案:使用多个连接,尽管SO上有一些答案明确地警告这个,因为它(引用)不应该被需要'。在这种情况下,需要IT。