小编典典

一个客户端的Redis WATCH MULTI EXEC

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

预期的结果 :在exec回调中得到N个错误,最后得到“ inc”变量= 10-N。

意外的结果 :exec回调中出现0个错误,但最终得到“ inc”变量= 1。

观看不适用于我的代码。

我发现此线程重做,并且watch +multi允许并发用户。他们说这是因为唯一的redis客户。

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

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

第1版:

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

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

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


阅读 574

收藏
2020-06-20

共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

这样一来,您就可以准确地得到上面编写的结果:“在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

了解redis如何执行命令非常重要。Redis是单线程的,来自所有连接的所有命令都一行一行地执行。Redis不能保证一个连接中的命令会连续执行(如果这里存在另一个连接),因此如果要确保命令执行了一个块(如果需要),则应该使用MULTI。但是为什么需要WA​​TCH?看看我上面的redis命令。您可以看到来自不同连接的命令混合在一起。并观看让您管理。

这在 文档中得到了很好的解释。请阅读!

2020-06-20