【问题标题】:Is there a way to acquire a lock in Redis? (Node.js)有没有办法在 Redis 中获取锁? (Node.js)
【发布时间】:2011-10-13 08:48:04
【问题描述】:

我的 Node.js 应用程序接受来自外部的连接。每个连接处理程序在 Redis 上读取一个 SET,最终修改该集合本身,然后继续。问题是同时另一个异步连接可以尝试读取相同的 SET 并尝试更新它或根据它读取的内容决定下一步。

我知道 Redis 尽最大努力实现原子化,但这对于我的用例来说还不够。想一想:读取集合以了解它是否已满(有一个业务规则)。如果它已满,那么就会发生一些事情。问题是如果只剩下一个插槽,两个半并发连接可能会认为每个都是最后一个。我得到一个溢出。

我有办法在很短的时间内保持连接“等待”另一个最终需要更新设置状态吗?

我认为这是一个极端情况,非常非常不幸......但你知道:)

使用另一把钥匙作为“锁”是一种选择,还是很臭?

【问题讨论】:

  • 我不想把萨尔瓦多的回答当作我的。他之前已经解决了这个问题。使用 SETNX 和 WATCH 来模拟锁。 github.com/antirez/redis/pull/41

标签: asynchronous concurrency node.js redis


【解决方案1】:

如何使用blpop 进行锁定。 blpop key 5 等待 key 5 秒。在开始时将项目(以识别队列不为空)放在键处。获取锁的连接应该从键中删除项目。然后下一个连接无法获取锁,因为为空,但 blpop 具有以下不错的属性:

多个客户端可以阻止同一个密钥。它们被放入一个 排队,所以第一个被送达的将是开始等待的那个 更早,以先到先得的方式。

当获得锁的连接完成任务后,它应该将item放回队列中,然后下一个等待的连接可以获得锁(item)。

【讨论】:

  • 似乎正是我所需要的。不过,我必须检查它如何在 Node.js 进程中执行。至少投票赞成:)
  • @Claudio 所以这是您正在寻找的答案,但您将另一个标记为正确答案? :"D
【解决方案2】:

您可能正在寻找WATCHMULTI/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

它的工作方式是MULTIEXEC 之间的所有命令都排队,但直到调用EXEC 才真正执行。当调用EXEC 时,在实际执行排队指令之前,它会检查sentinel_key 是否在设置WATCH 后发生了变化;如果有,则返回(nil),并丢弃排队的命令。否则,命令将作为一个块自动执行,并返回执行的命令数(在本例中为 1),让您知道您赢得了比赛并且可以调用 do_something()

它在概念上类似于fork()/exec() Unix 系统调用——fork() 的返回值告诉你你是哪个进程(父进程或子进程)。在这种情况下,它会告诉您是否赢得了比赛。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2020-12-12
    • 2022-12-12
    • 1970-01-01
    • 2011-03-03
    相关资源
    最近更新 更多