一尘不染

Redis BITSET和WATCH

redis

我正在使用Redis创建一种算法来声明某个范围内未使用的整数。

此解决方案使用BITPOSBITSET,并且为了避免出现竞争情况,我也使用WATCH/ MULTI/
EXEC。为了测试并发方面,我创建了一个bash脚本,该脚本同时尝试并行查找10个空闲数字,以调查EXEC命令的可能结果。

我发现EXEC即使从另一个客户端修改了监视的密钥,也永远不会返回null。我添加了一些延迟,以至于有足够的时间来引发并发修改,这会触发监视机制,从而导致EXEC失败,但事实并非如此。

所以基本上我有这段代码:

while (true) {
  WATCH mykey
  number = BITPOS mykey, 0
  if (number > maxNumber) THROW ERROR

  (deliberate delay)

  MULTI
  SETBIT mykey, number, 1
  if EXEC != null return number
}

也是一个循环调用SETBIT mykey, N, 1N = 1..10,在10个不同的进程。

我发现EXEC,即使在监视的时间内肯定由另一个进程修改了密钥,也永远不会返回null。

问题:

  1. 是否WATCH完全不支持基于BIT的Redis命令?
  2. 如果得到支持,为什么在这种情况下不触发它?我是否在错误地测试/挑衅?据我了解,如果密钥已在监视的时间内 被另一个客户端/连接 修改,并且从10个不同的Linux进程(每个进程都创建自己的连接)中调用此密钥似乎符合该要求,WATCH应该EXEC失败吗? __
  3. 在这种特殊情况下,也WATCHMULTI实际提供的东西吗?BITSET返回该位的先前值,因此不应仅通过以下伪代码算法来保证原子性:
    while (true) {
      number = BITPOS mykey, 0
      if (number > maxNumber) THROW ERROR
    
      wasUsed = SETBIT mykey, number, 1
    
      if (!wasUsed) {
        return number
      }
    }
    

阅读 744

收藏
2020-06-20

共1个答案

一尘不染

  1. 没有文档表明WATCH不支持位设置命令。

  2. 您的代码对我来说看起来很正确,因此很难说出为什么它不起作用。为了进一步研究它,您必须提供MCVE而不是伪代码。然而…

  3. 是的,这里不需要事务,此算法应保证原子性。

2020-06-20