Redis的WATCH多EXEC由一个客户端(Redis WATCH MULTI EXEC by o

2019-08-19 03:53发布

我使用的NodeJS +快速+ Redis的上RedisOnGo + node_redis作为客户端。 我想到了很多并发的,所以试图测试观看。 这个例子将不包含快递,只是必要的东西。

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)
            })
        })
    }
})

预期结果 :得到在EXEC回调Ñ错误和终于得到“INC”变量= 10-N。

意想不到的结果 :让在EXEC回调0错误,但终于得到“公司”变量= 1。

手表不与我的代码工作。

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

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

另请注意,我必须进行身份验证的Redis服务器。 提前致谢!

EDITION 1:

我能使其工作使用本地Redis的实例(所以我不使用client.auth)通过创建每款腕表-MULTI-EXEC迭代之前一个新的客户端连接。 不知道这是件好事,虽然,但结果现在是100%准确。

第2版制造,如果我创建的每个WATCH-MULTI-EXEC迭代之前一个新的客户端连接,然后就client.auth并等待client.on它的工作。

现在的问题依然存在,那是正确的,我为每个迭代的新客户端连接?

Answer 1:

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

请记住 - Node.js的是一个线程的应用程序。 Node.js的使用异步输入输出,但命令应该在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

所以,你得到完全,你写了上面的结果:“在获得高管回调0错误,但终于得到‘公司’变量= 1”。

那是正确的,你创建的每个迭代新客户端连接?

对于此示例 - 是的,它的解决您的问题。 在一般 - 这取决于你想要的“并行”查询多少运行。 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的不能保证从一个连接该命令将连续执行(如果这里存在另一个连接),所以你应该多要是想确保你的命令执行一个块(如果需要的话)。 但是,为什么WATCH需要的? 看看我的Redis上面的命令。 你可以看到不同的连接来该命令混合。 而手表让你来管理这一点。

这中美丽的解释文件 。 请阅读它!



Answer 2:

我收到了你的问题最后。

如果你想测试WATCH并发,我认为你需要改变你的代码。 据我们所知。 仅观看监控的值发生变化,没有得到值操作。 所以在当前的代码,所有的get命令将被成功执行,并得到0 ,那么他们将设置inc1 。 所有的设定值是相同的( 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)
        })
    })
}

我在我的电脑进行了测试。

[26/11/2013 18:51:09389] [INFO]控制台 - [1, 'OK']

[26/11/2013 18:51:09390] [INFO]控制台 - [2,1 'OK']

[26/11/2013 18:51:09390] [INFO]控制台 - [3 'OK']

[26/11/2013 18:51:09390] [INFO]控制台 - [4 'OK']

[26/11/2013 18:51:09391] [INFO]控制台 - [5,1 'OK']

[26/11/2013 18:51:09391] [INFO]控制台 - [6, 'OK']

[26/11/2013 18:51:09392] [INFO]控制台 - [7, 'OK']

[26/11/2013 18:51:09392] [INFO]控制台 - [8, 'OK']

[26/11/2013 18:51:09393] [INFO]控制台 - [9, 'OK']

[26/11/2013 18:51:09393] [INFO]控制台 - [10, 'OK']



Answer 3:

如果你想使用事务/原子多操作,但要做到这一点使用共享连接,因为据我所知,你唯一的选择是用LUA。

我用LUA脚本的Redis中的一些事情,以及与LUA的事情是整个脚本将原子执行,这是相当方便。 你必须要知道,虽然这意味着,如果你有你正在缓慢Redis的使用你的服务器大家一个缓慢的LUA脚本。

此外,使用LUA即使你可以在不同的按键操作时,如果使用在你的脚本不止一个键,你将无法使用Redis的集群一旦被释放了解。 这是因为,使用集群时,按键会被分配到不同的Redis流程,使您的LUA脚本可能无法访问所有的人都在一台服务器上。

在任何情况下,Redis的集群的问题将发行多的时候,因为MULTI将不允许在群集上设置不同的密钥是相同的。

干杯,

Ĵ



文章来源: Redis WATCH MULTI EXEC by one client