ZooKeeper中的竞争条件和基于Python的消息队列

ZooKeeper中的竞争条件和基于Python的消息队列,python,locking,message-queue,race-condition,apache-zookeeper,Python,Locking,Message Queue,Race Condition,Apache Zookeeper,我将ZooKeeper作为一个简单的消息队列进行评估,并编写了两个非常简单的脚本:mq feeder和mq consumer。下面的馈线主要将20个作业推送到队列,然后监视队列状态(正在消耗的作业): 下面的使用者被启动了几次(在我的测试中最多有3个并发进程),它获取作业列表,对其进行迭代以找到未锁定的作业,对其进行处理(睡眠随机数秒以模拟某些工作),完成后删除作业,然后删除锁: from kazoo.client import KazooClient from kazoo.exceptions

我将ZooKeeper作为一个简单的消息队列进行评估,并编写了两个非常简单的脚本:mq feeder和mq consumer。下面的馈线主要将20个作业推送到队列,然后监视队列状态(正在消耗的作业):

下面的使用者被启动了几次(在我的测试中最多有3个并发进程),它获取作业列表,对其进行迭代以找到未锁定的作业,对其进行处理(睡眠随机数秒以模拟某些工作),完成后删除作业,然后删除锁:

from kazoo.client import KazooClient
from kazoo.exceptions import NodeExistsError
from time import sleep
import random

zk = KazooClient(hosts='xxx')
zk.start()
zk.ensure_path("/locks")
zk.ensure_path("/queue")

while 1:
  jobs = sorted(zk.get_children('/queue'))
  if jobs:
    for i in jobs:
      print "Checking job: %s" % i
      try:
        zk.create("/locks/%s" % i)
      except NodeExistsError:
        print "Job is locked, skipping!"
        pass
      else:
        print "Job is unlocked, processing."
        sleep(random.randrange(5))
        zk.delete("/queue/%s" % i)
        print "Deleted processed job, deleting the lock."
        zk.delete("/locks/%s" % i)
        pass
  else:
    print "There's no locks in the queue."
    pass
我所看到的问题是,我无法跟踪的是,消费者流程正在以以下方式退出:

Traceback (most recent call last):
  File "zk_consumer.py", line 24, in <module>
    zk.delete("/queue/%s" % i)
  File "/Library/Python/2.7/site-packages/kazoo/client.py", line 1055, in delete
    return self.delete_async(path, version).get()
  File "/Library/Python/2.7/site-packages/kazoo/handlers/threading.py", line 107, in get
    raise self._exception
kazoo.exceptions.NoNodeError: ((), {})
回溯(最近一次呼叫最后一次):
文件“zk_consumer.py”,第24行,在
zk.delete(“/queue/%s”%i)
文件“/Library/Python/2.7/site packages/kazoo/client.py”,第1055行,删除
返回self.delete\u async(路径,版本).get()
get中的文件“/Library/Python/2.7/site packages/kazoo/handlers/threading.py”,第107行
提出自己的意见
kazoo.exceptions.NoNodeError:((),{})

虽然最后一个进程始终保持检查单个作业,但该作业仍在队列中,但始终处于锁定状态。显然,我有一些逻辑上的错误,我认为这会导致比赛状态,但我已经花了一些时间,我似乎无法发现它。我在这里是做错了什么,还是ZooKeeper不是简单工作队列的可行解决方案?

您的代码很快。考虑这个序列,

T1                      T2
read queue/1     
                        read queue/1
                        write lock/1
                        delete queue/1
                        delete lock/1
write lock/1 
delete queue/1 (FAIL, no node!)

锁定后,您需要再次阅读,以确保没有其他人删除了队列1。

您是正确的,但我还发现有一种更正确的方法来实现我的需要,即使用Kazoo的锁定队列方法,如中所示
T1                      T2
read queue/1     
                        read queue/1
                        write lock/1
                        delete queue/1
                        delete lock/1
write lock/1 
delete queue/1 (FAIL, no node!)