我的Node.js应用程序接受来自外部的连接。每个连接处理程序读取Redis上的SET,最终修改集合本身,然后继续。问题是,同时另一个异步连接可以尝试读取相同的SET并尝试更新它或根据它读取的内容决定其下一步。
我知道Redis尽力做到原子,但这对我的用例来说还不够。想一想:读取集合以了解它是否已满(有一个业务规则)。如果它是满的,那么就会发生一些事情。问题是如果只剩下一个插槽,两个半并发连接可能会认为每个插槽都是最后一个。而且我得到了溢出。
我有办法在很短的时间内保持连接“等待”,其他人最终需要更新设置状态吗?
我认为这是一个极端的案例,非常非常不合理......但你知道:)
使用另一个键作为“锁定”是一个选项,还是会发臭?
答案 0 :(得分:3)
如何使用blpop进行锁定。 blpop key 5
等待5秒key
。在开始时,在键处输入项目(以识别队列不为空)。获取锁的连接应从键中删除项。然后下一个连接无法获取锁,因为空,但是blpop具有以下不错的属性:
多个客户端可以阻止相同的密钥。他们被投入了 排队,所以第一个被服务的将是那个开始等待的人 早些时候,以第一次BLPOP先到先得的方式。
当获取锁定的连接完成任务后,它应该将项目放回队列中,然后下一个连接等待可以获取锁定(项目)。
答案 1 :(得分:2)
您可能正在寻找WATCH
MULTI/EXEC
。这是两个线程遵循的模式:
WATCH sentinel_key
GET value_of_interest
if (value_of_interest = FULL)
MULTI
SET sentinel_key = foo
EXEC
if (EXEC returned 1, i.e. succeeded)
do_something();
else
do_nothing();
else
UNWATCH
这种方法的工作原理是MULTI
和EXEC
之间的所有命令都排队,但在调用EXEC
之前不会实际执行。调用EXEC
时,在实际执行排队指令之前,它会检查sentinel_key
是否已更改,因为WATCH
已设置;如果有,则返回(nil)
并排除排队的命令。否则命令将作为块原子执行,并返回执行的命令数(在本例中为1),让您知道您赢得了比赛并且可以调用do_something()
。
它在概念上类似于fork()/exec()
Unix系统调用 - 来自fork()的返回值告诉您您是哪个进程(父进程或子进程)。在这种情况下,它会告诉您是否赢得了比赛。