如果2个 worker 同时在一个排序集中的同一元素上调用ZREM,会发生什么?它会向真正移除元素的工作人员返回true,而向另一个 worker 返回false来表明该元素不存在,还是对两个都返回true?换句话说,ZREM是内部原子的吗?

最佳答案

Redis(主要是)是单线程的,因此它的所有操作都是原子的,ZREM也不异常(exception)。但是,您的问题实际上是关于原子地执行“ZPOP”,因此有两种可能的方法。

选项1:WATCH / MULTI / EXEC

在伪代码中,这是乐观交易的外观:

:start
WATCH somekey
member = ZREVRANGE somekey 0 0
MULTI
ZREM somekey member
if not EXEC goto :start // or quit trying

选项2:Lua脚本
zpop.lua:

local member = redis.call('ZREVRANGE', KEYS[1], 0, 0)
return redis.call('ZREM', KEYS[1], member)

redis-cli --eval zpop.lua somekey

注意-原子性的重要性
如果您决定不使用这些确保原子性的机制,则会比您想象的更快地遇到问题。这是一种可能的情况:
Process A                Redis Server            Process B
ZREVRANGE ------------>
          <------------- foo
                                      <--------- ZADD +inf bar
                                   OK --------->
ZREM foo -------------->
         <-------------- 1

在上面的示例中,在A提取foo之后,B插入了一个荒唐的高分的bar,因此它成为集合中的顶部元素。但是,A将继续并删除以前位于顶部的foo。

08-27 22:25