Redis WATCH MULTI EXEC 由一个客户端执行 [英] Redis WATCH MULTI EXEC by one client

查看:23
本文介绍了Redis WATCH MULTI EXEC 由一个客户端执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 RedisOnGo + node_redis 上使用 NodeJS + Express + Redis 作为客户端.我期望有很多并发性,因此尝试测试 WATCH.此示例不包含 Express,仅包含必要的内容.

I am using NodeJS + Express + Redis on RedisOnGo + node_redis as a client. I expect a lot of concurrency, so trying to test WATCH. This example won't contain Express, just necessary stuff.

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.

Expecting result: getting N errors in exec callbacks and finally getting "inc" variable = 10-N.

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

Unexpected result: getting 0 errors in exec callbacks but finally getting "inc" variable = 1.

Watch 不适用于我的代码.

Watch doesn't work with my code.

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

I have found this thread redis and watch + multi allows concurrent users. They say it is because of the only redis client.

然后我找到了这个帖子 我应该创建一个每个连接的新 Redis 客户端?.他们说绝对不推荐"为每笔交易生成一个新客户端.我迷路了.

Then I found this thread Should I create a new Redis client for each connection?. They say that generating a new client for each transaction "is definitely not recommended". I am lost.

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

Please also note, that I have to authenticate to Redis server. Thanks in advance!

第 1 版:

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

I was able to make it work using local Redis instance (so I do not use client.auth) by creating a new client connection before each WATCH-MULTI-EXEC iteration. Not sure if it is good though, but results now are 100% accurate.

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

EDITION 2 Made it work if I create a new client connection before each WATCH-MULTI-EXEC iteration and then do client.auth and wait for client.on.

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

The question still exists, is it OK that I create new client connections for each iteration?

推荐答案

您的结果完全可以预测.理所当然.

Your result is entirely predictable. And rightly so.

请记住 - node.js 是一个线程应用程序.Node.js 使用异步输入-输出,但命令应该在 redis 中严格按请求-响应"顺序发送.因此,当您只使用一个连接到 redis 服务器时,您的代码和您的请求严格并行执行.

Keep in mind - node.js is one thread application. Node.js use asynchronous input-output, but the commands should be sent in redis strictly sequential "request-response". So your code and your requests executed strictly parallel while your are using just one connection to redis server.

看看你的代码:

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

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

To confirm this do this steps:

  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.".

So that you get exactly the results that you wrote above: "getting 0 errors in exec callbacks but finally getting "inc" variable = 1.".

是否可以为每次迭代创建新的客户端连接?

对于此示例 - 是的,它解决了您的问题.一般来说 - 这取决于您要运行多少个并发"查询.Redis 仍然是一个线程,因此这种并发"意味着将命令批处理并发到 Redis 引擎的唯一方式.

For this sample - yes, its solves your problem. In general - it depends on how many "concurrent" query you want to run. Redis is still one threaded so this "concurrent" means just way to concurrent command batch to redis engine.

例如,如果使用 2 个连接,monitor 可能会给出如下信息:

For example, if use 2 connections the monitor could give something like this:

 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 命令.您可以看到来自不同连接的命令混合在一起.并且手表允许您管理此.

Its very important to understand how redis execute your commands. Redis is single threaded, all command from all connection executed one-by-one in a row. Redis does not guarantee that command from one connection would be executed in a row (if here is another connections present) so your should MULTI if want be sure that your commands executed one block (if need it). But why WATCH needed? Look at my redis commands above. You can see that command coming from different connections are mixed. And watch allow you to manage this.

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

This beautifully explained in the documentation. Please read it!

这篇关于Redis WATCH MULTI EXEC 由一个客户端执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆