【问题标题】:redis: atomic LPOP and SADD possible?redis:原子 LPOP 和 SADD 可能吗?
【发布时间】:2012-08-21 12:44:06
【问题描述】:

是否可以从列表中自动弹出一个项目并将其添加到集合中?

我的情况是,我有一个独特项目的“工作队列”列表,我想跟踪“进行中”集合中正在处理的内容。如果我的工作进程在处理项目时崩溃,这也将允许“进行中”集中的项目重新排队。

我希望它是原子的,这样从列表中弹出的任何内容都将始终在集合中。我只是不知道如何使用 MULTI/EXEC 来做到这一点,即:

redis> MULTI
OK
redis> LPOP workqueue
"foobar"
redis> SADD inprog "foobar"
redis> EXEC

【问题讨论】:

    标签: list queue redis set


    【解决方案1】:

    为什么您希望您的“进行中”收藏成为一个 Set?您可以简单地为正在进行的项目使用列表。

    RPOPLPUSH“Right Pop,Left Push”命令正是针对这个用例制定的。

    以原子方式返回并移除列表的最后一个元素(尾部) 存储在源中,并将元素推送到第一个元素(头部) 存储在目的地的列表

    如果您确实想为正在进行的项目使用 Set,则必须使用 lua 脚本并使用 eval 调用它。

    【讨论】:

    • 因为集合似乎是更合适的数据结构。由于我可能会将多个工作进程添加到“进行中”结构中,因此我认为从“进行中”列表中完成/删除项目会更加困难且效率较低(即动态索引作为项目推送/弹出)。但我刚刚注意到列表的 LREM 命令,因为我的所有项目都是唯一的,所以它会起作用。但是,删除项目的效率仍然较低:在这种情况下,SREM 是 O(1),LREM 是 O(n),其中 n 是列表的长度。
    • +1 这是一个很好的理由。由于您的进行中列表是有界的,因此 O(n) 根本不重要,它不会很昂贵。我可能会补充一点,一小组整数实际上将具有 O(log N) 时间复杂度,因为它是作为整数集实现的。但这些在实践中根本无关紧要,因为列表或集合是有界的。
    • @SripathiKrishnan 将集合作为队列消息的存储的用例是消息可以从重复数据删除中受益——例如,重复的缓存预热请求消息只能处理一次,并且一些无用的处理被跳过。
    【解决方案2】:

    MULTI/EXEC 似乎不起作用,因为第二个命令取决于第一个命令的返回值,但是在调用 EXEC 之前,这两个命令都不会执行。如果您使用的是 Redis 2.6(目前在 RC 中),您可以通过eval 使用 lua 脚本。

    一般来说,我认为原子性在这里不是那么重要。在这种情况下并没有真正的竞争条件。唯一可能发生的坏事是,如果服务器在将项目从队列中弹出并将其添加到集合之间的时间内崩溃,这似乎不太可能发生。

    【讨论】:

    • 同意答案的 multi/exec 和 eval 部分。但我不同意原子性不是问题。如果有多个客户端尝试并行推送/弹出,您将遇到竞争条件。该错误将非常难以追踪。
    猜你喜欢
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多