2

我正在尝试使用两个 EC2 可用区中的两个 redis 主服务器构建一个作业队列。所有 LPUSH 操作都在应用层对两个 AZ 中的两台主机完成。理想情况下,我会使用GitHub 的 resque,但 resque似乎没有任何关于多个 AZ 中的多个 master 的概念。

我需要确保只有一名工人在从事给定的工作。一些工人将在 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
4

2 回答 2

1

你要做的本质上是主主复制,无论是队列还是其他,redis都不支持,你的伪代码有竞争条件。只是在做:

m1lock = master1.SETNX "lock.#{job_id}"
m2lock = master2.SETNX "lock.#{job_id}"

表示在您执行此操作时,另一名工人可以接手这项工作,并且两名工人将同时工作。我不认为 redis 非常适合您的模式,而且我不知道任何可以以这种方式工作的队列服务器,但话说回来,我不知道很多这样的服务器,所以我确定有。

如果你对你的工作进行负载平衡,以便一次只有一个 master 得到一份工作,这是可能的,但是你实际上有两个队列,而不是一个。

于 2012-05-31T07:55:23.453 回答
0

I'm curious... if you're already in the AWS environment, why wouldn't you choose instead to use Amazon's SQS service? I've worked with it in the past and realize it's a bit of a pain in the ass, but it's Amazon's most mature service and it's purpose built for this scenario.

于 2012-06-01T16:20:46.623 回答