我正在尝试使用两个 EC2 可用性区域中的两个 redis 主服务器构建一个作业队列。所有 LPUSH 操作都在应用层中完成到两个 AZ 中的两个 master 机器。理想情况下我会使用 GitHub's resque , 但重新请求 does not seem to have any notion多个 AZ 中的多个 master。
我需要确保只有一名 worker 在从事给定的工作。一些工作人员将在 AZ 1A 中与 1A 中的 redis 机器通信,而一些将在 AZ 1B 中与 1B 中的机器通信。我需要避免 1A 中的工作人员和 1B 中的工作人员都从不同的 redis master 中获取相同的工作并尝试同时处理它的情况。
这个 worker 伪代码是否有任何我可能错过的竞争条件?
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
最佳答案
本质上你想做的是master-master replication,无论是队列还是其他什么,redis都不支持,而且你的伪代码存在race conditions。 只是在做:
m1lock = master1.SETNX "lock.#{job_id}"
m2lock = master2.SETNX "lock.#{job_id}"
意味着另一个 worker 可以在你做这件事的时候接手这项工作,两个 worker 将同时工作。 我不认为 redis 是您的模式的理想选择,而且我不知道有任何队列服务器可以那样工作,但话又说回来,我不知道有多少这样的服务器,所以我确定有。
如果您对您的工作进行负载平衡,以便一次只有一个主服务器获得一份工作,这是可能的,但实际上您有两个队列,而不是一个。
关于queue - 跨多个redis主服务器实现一个队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10822812/