我正在尝试使用两个EC2可用区中的两个redis主服务器构建一个作业队列。所有LPUSH操作都在应用层中完成,同时在两个AZ中的两台主机上完成。理想情况下,我会使用GitHub's resque,但在多个AZ中重新使用多个母版的does not seem to have any notion。
我需要确保只有一名工人正在从事某项工作。一些工人将在AZ 1A与1A中的redis机器通信,而一些工作人员将在AZ 1B与1B机器通话。我需要避免这样的情况:1A中的工作人员和1B中的工作人员都从不同的redis主人那里取得同样的工作,并尝试同时处理它。
这个工作者伪代码是否有任何我可能错过的竞争条件?
job_id = master1.BRPOPLPUSH "queue", "working"
m1lock = master1.SETNX "lock.#{job_id}"
m2lock = master2.SETNX "lock.#{job_id}"
completed = master1.ZSCORE "completed", job_id
if completed
# must have been completed just now on other server, no-op
master1.LREM "working", 0, job_id
master1.del "lock.#{job_id}"
master2.del "lock.#{job_id}"
elsif not m1lock or not m2lock
# other server is working on it? We will put back at the end of our queue
master1.LPUSH "queue", job_id
master1.LREM "working", 0, job_id
master1.del "lock.#{job_id}" if m1lock
master2.del "lock.#{job_id}" if m2lock
else
# have a lock, it's not complete, so do work
do_work(job_id)
now = Time.now.to_i
master1.ZADD "completed", now, job_id
master2.ZADD "completed", now, job_id
master1.del "lock.#{job_id}"
master2.del "lock.#{job_id}"
master1.LREM "working", 0, job_id
master2.LREM "queue", 0, job_id # not strictly necessary b/c of "completed"
end
答案 0 :(得分:1)
你要做的实质上是master-master复制,无论是队列还是其他任何东西,redis都不支持它,你的伪代码有竞争条件。 只是这样做:
m1lock = master1.SETNX "lock.#{job_id}"
m2lock = master2.SETNX "lock.#{job_id}"
意味着另一名工人可以在您这样做时接受这项工作,两名工人将立即开展工作。 我不认为redis是你的模式的理想选择,我不知道任何可以这样工作的队列服务器,但是我再也不知道很多这样的服务器,所以我确信它有。
如果你平衡你的工作以便只有一个主人一次获得一份工作,那么这是可能的,但是你本质上有两个队列,而不是一个。
答案 1 :(得分:0)
我很好奇......如果您已经在AWS环境中,为什么不选择使用亚马逊的SQS服务呢?我过去曾经使用它,并意识到这是一个痛苦的屁股,但它是亚马逊最成熟的服务,它的目的是为这种情况。