Redis由一名客户观看MULTI EXEC

我在RedisOnGo + node_redis上使用NodeJS + Express + Redis作为客户端。 我期望很多的并发性,所以试图testingWATCH。 这个例子不包含Express,只是必要的东西。

var redis = require("redis") var rc = redis.createClient(config.redis.port, config.redis.host) rc.auth(config.redis.hash, function(err) { if (err) { throw err } }) rc.on('ready', function () { rc.set("inc",0) for(var i=1;i<=10;i++){ rc.watch("inc") rc.get("inc",function(err,data){ var multi = rc.multi() data++ // I do know I can use rc.incr(), this is just for example multi.set("inc",data) multi.exec(function(err,replies){ console.log(replies) }) }) } }) 

期望的结果是 :在execcallback中获得N个错误,最后得到“inc”variables= 10-N。

意外的结果 :得到0callbackexeccallback错误,但最终变得“inc”variables= 1。

手表不能用我的代码。

我发现这个线程redis和手表+多允许并发用户 。 他们说这是因为唯一的redis客户端。

然后我发现这个线程我应该为每个连接创build一个新的Redis客户端? 。 他们说,为每笔交易生成一个新客户“绝对不被推荐”。 我搞不清楚了。

还请注意,我必须对Redis服务器进行身份validation。 提前致谢!

版本1:

通过在每个WATCH-MULTI-EXEC迭代之前创build新的客户端连接,我能够使用本地Redis实例工作(所以我不使用client.auth)。 不知道这是否是好的,但现在的结果是100%准确的。

EDITION 2如果我在每个WATCH-MULTI-EXEC迭代之前创build一个新的客户端连接,然后执行client.auth并等待client.on,则工作。

问题依然存在,我可以为每个迭代创build新的客户端连接吗?

你的结果是完全可预测的。 正确的。

请记住 – node.js是一个线程应用程序。 Node.js使用asynchronousinput输出,但是这些命令应该在redis严格顺序的“请求 – 响应”中发送。 所以,当你使用一个连接到redis服务器的时候,你的代码和你的请求是严格平行的。

看看你的代码:

 rc.on('ready', function () { rc.set("inc",0) for(var i = 1; i <= 10; i++){ rc.watch("inc") //10 times row by row call get function. It`s realy means that your written //in an asynchronous style code executed strict in series. You are using just //one connection - so all command would be executed one by one. rc.get("inc",function(err,data){ //Your data variable data = 0 for each if request. var multi = rc.multi() data++ //This operation is not atomic for redis so your always has data = 1 multi.set("inc",data) //and set it multi.exec(function(err,replies){ console.log(replies) }) }) } }) 

要确认这一点,请执行以下步骤

  1. 连接到redis并执行monitor命令。
  2. 运行你的node.js应用程序

输出将是

  SET inc 0 WATCH inc GET inc .... get command more 9 times MULTI SET inc 1 EXEC .... command block more 9 times 

这样你就可以得到上面写的结果:“在execcallback中获得0错误,但最终得到”inc“variable = 1。”

您可以为每个迭代创build新的客户端连接吗?

对于这个例子 – 是的,它解决了你的问题。 一般来说 – 这取决于你想运行多less个“并发”查询。 Redis仍然是一个线程,所以这个“并发”意味着正确的方式来批量并发命令redis引擎。

例如,如果使用2个连接, monitor可以给这样的东西:

  1 SET inc 0 //from 1st connection 2 WATCH inc //from 1st connection 3 SET inc 0 //from 2nd connection 4 GET inc //from 1nd connection 5 WATCH int //from 2nd connection 6 GET inc //from 2nd connection 7 MULTI //from 1st connection 8 SET inc 1 //from 1st connection 9 MULTI //from 2nd connection 10 SET inc 1 //from 2nd connection 11 EXEC //from 1st failed becouse of 2nd connection SET inc 0 (line 3) //was executed after WATCH (line 2) 12 EXEC //success becouse of MULTI from 1st connection was failed and SET inc 1 from first //connection was not executed -------------------------------------------------------------------------------> time | | | | | | | | | | | | connection 1 set watch | get | | multi set | | exec(fail) | connection 2 set watch get multi set exec 

理解redis如何执行你的命令非常重要。 Redis是单线程的,所有连接中的所有命令都是连续执行的。 Redis不保证来自一个连接的命令将在一行中执行(如果这里是另一个连接存在的话),所以如果你想要确保你的命令执行了一个块(如果需要的话),你应该使用MULTI。 但是为什么WATCH需要? 看看我上面的redis命令。 你可以看到来自不同连接的命令是混合的。 而手表让你pipe理这个。

这在文档中有很好的解释。 请阅读!

我终于得到了你的问题。

如果你想testingWATCH的并发性,我认为你需要改变你的代码。 据我们所知。 WATCH只监视值的变化,没有得到值操作。 所以在你当前的代码中,你所有的get命令都会被成功的执行并得到0 ,那么它们将会被设置为1 。 所有的设定值都是一样的( 1 ),所以手表不会失败。

在这种情况下,我们需要确保write操作不仅受到保护,而且还要read 。 在你设置inc之前,你需要watch和修改另一个作为悲观锁的密钥,然后我们可以获得和更改inc 。 这样就能确保你的期望。

 rc.set("inc",0) for(var i=1;i<=10;i++){ rc.watch("inc-lock") rc.get("inc",function(err,data){ var multi = rc.multi() data++ multi.incr("inc-lock") multi.set("inc",data) multi.exec(function(err,replies){ console.log(replies) }) }) } 

我在我的电脑上testing过。

[2013-11-26 18:51:09.389] [INFO] console – [1,'OK']

[2013-11-26 18:51:09.390] [INFO] console – [2,'OK']

[2013-11-26 18:51:09.390] [INFO] console – [3,'OK']

[2013-11-26 18:51:09.390] [INFO] console – [4,'OK']

[2013-11-26 18:51:09.391] [INFO] console – [5,'OK']

[2013-11-26 18:51:09.391] [INFO] console – [6,'OK']

[2013-11-26 18:51:09.392] [INFO] console – [7,'OK']

[2013-11-26 18:51:09.392] [INFO] console – [8,'OK']

[2013-11-26 18:51:09.393] [INFO] console – [9,'OK']

[2013-11-26 18:51:09.393] [INFO] console – [10,'OK']

如果你想使用事务/primefacesMULTI操作,但你想这样做使用共享连接,据我所知你唯一的select是使用LUA。

我在redis中使用LUA脚本编写了一些东西,而LUA的东西是整个脚本都会自动执行,这是非常方便的。 你必须意识到这一点,这意味着如果你有一个缓慢的LUA脚本,你正在使用你的服务器的每个人的redis缓慢。

此外,即使您可以使用不同的密钥来使用LUA,也请注意,如果您在脚本中使用了多个密钥,那么在发布后,您将无法使用Redis群集。 这是因为在使用集群时,密钥将分配给不同的Redis进程,因此您的LUA脚本可能无法访问单个服务器上的所有这些进程。

在任何情况下,发出MULTI时redis集群的问题都是一样的,因为MULTI将不被允许在集群上设置不同的密钥。

干杯,

Ĵ