我使用的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它的工作。
现在的问题依然存在,那是正确的,我为每个迭代的新客户端连接?
你的结果是完全可以预测的。 这是正确的。
请记住 - 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)
})
})
}
})
为了证实这一点做到这一点的步骤:
- 连接到Redis的并执行
monitor
命令。 - 运行您的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上面的命令。 你可以看到不同的连接来该命令混合。 而手表让你来管理这一点。
这中美丽的解释文件 。 请阅读它!
我收到了你的问题最后。
如果你想测试WATCH并发,我认为你需要改变你的代码。 据我们所知。 仅观看监控的值发生变化,没有得到值操作。 所以在当前的代码,所有的get
命令将被成功执行,并得到0
,那么他们将设置inc
至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)
})
})
}
我在我的电脑进行了测试。
[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']
如果你想使用事务/原子多操作,但要做到这一点使用共享连接,因为据我所知,你唯一的选择是用LUA。
我用LUA脚本的Redis中的一些事情,以及与LUA的事情是整个脚本将原子执行,这是相当方便。 你必须要知道,虽然这意味着,如果你有你正在缓慢Redis的使用你的服务器大家一个缓慢的LUA脚本。
此外,使用LUA即使你可以在不同的按键操作时,如果使用在你的脚本不止一个键,你将无法使用Redis的集群一旦被释放了解。 这是因为,使用集群时,按键会被分配到不同的Redis流程,使您的LUA脚本可能无法访问所有的人都在一台服务器上。
在任何情况下,Redis的集群的问题将发行多的时候,因为MULTI将不允许在群集上设置不同的密钥是相同的。
干杯,
Ĵ