ZooKeeper中的竞争条件和基于Python的消息队列
我将ZooKeeper作为一个简单的消息队列进行评估,并编写了两个非常简单的脚本:mq feeder和mq consumer。下面的馈线主要将20个作业推送到队列,然后监视队列状态(正在消耗的作业): 下面的使用者被启动了几次(在我的测试中最多有3个并发进程),它获取作业列表,对其进行迭代以找到未锁定的作业,对其进行处理(睡眠随机数秒以模拟某些工作),完成后删除作业,然后删除锁: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
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!)