Redis WATCH MULTI EXEC由一个客户提供

igo*_*lov 10 javascript redis node.js node-redis

我在RedisOnGo + node_redis上使用NodeJS + Express + Redis作为客户端.我期待很多并发,所以试图测试WATCH.这个例子不包含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)
            })
        })
    }
})
Run Code Online (Sandbox Code Playgroud)

期待结果:在exec回调中得到N个错误,最后得到"inc"变量= 10-N.

意外的结果:在exec回调中得到0错误,但最终得到"inc"变量= 1.

Watch无法使用我的代码.

我发现这个线程redis和watch + multi允许并发用户.他们说这是因为唯一的redis客户端.

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

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

第1版:

通过在每次WATCH-MULTI-EXEC迭代之前创建新的客户端连接,我能够使用本地Redis实例(因此我不使用client.auth).不确定它是否好,但结果现在是100%准确.

版本2 如果我在每次WATCH-MULTI-EXEC迭代之前创建一个新的客户端连接,然后执行client.auth并等待client.on,它就可以工作了.

问题仍然存在,我是否可以为每次迭代创建新的客户端连接?

mis*_*ion 18

您的结果完全可以预测.这是正确的.

请记住 - 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) 
            })
        })
    }
})
Run Code Online (Sandbox Code Playgroud)

要确认这一步,请执行此步骤:

  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
Run Code Online (Sandbox Code Playgroud)

这样你就可以得到你上面写的结果:"在exec回调中得到0个错误,但最终得到"inc"变量= 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
Run Code Online (Sandbox Code Playgroud)

理解redis如何执行命令非常重要.Redis是单线程的,所有连接中的所有命令都是逐行执行的.Redis不保证来自一个连接的命令将连续执行(如果此处存在另一个连接),所以如果要确保您的命令执行一个块(如果需要),则应该是MULTI.但为什么需要WA​​TCH呢?看看我上面的redis命令.您可以看到来自不同连接的命令是混合的.并且手表允许您管理这个.

这在文档中精美地解释了.请仔细阅读!