Я пытаюсь создать очередь заданий с использованием двух главных серверов redis в двух зонах доступности EC2. Все операции LPUSH выполняются в прикладном уровне на обеих мастер-машинах в обоих AZ. В идеале я бы использовал GitHub's resque, но resque does not seem to have any notion нескольких мастеров в нескольких AZ.Реализация очереди на нескольких серверах redis
Мне нужно обеспечить, чтобы только один работник работал над заданием. Некоторые работники будут в AZ 1A разговаривать с машиной redis в 1A, а некоторые будут в 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
SETNX возвращает сбой, если он не может получить блокировку, поэтому теоретически они оба потерпят неудачу, если они будут выполняться одновременно, а работа не будет выполнена, поэтому я думаю, что все будет хорошо (я полагаю, в одном случае, если бы только 1 задание в очереди. Я мог бы оказаться в ситуации, когда я не мог блокировать многократно, поэтому мне может потребоваться какой-то период отсрочки, но в реальном мире мои очереди будут переменной длиной, поэтому я сомневаюсь, что останусь в этом случае очень долго). Я знаю, что redis не поддерживает это, поэтому мне нужно сделать это на уровне приложений, так как машины EC2 и AZ могут и не работают ... – esilver
, если один из клиентов сначала обратится к первому мастеру, а не к ближайшему мастеру действительно ли он отличается от цепной репликации (master-slave/master-slave)? –
В моем фактическом коде клиент пытается связаться со своим ближайшим мастером (тот, который находится в его AZ), и если он не может, он отправится к мастеру в другой AZ. (FWIW во время Amazon Cloudpocalypse в апреле 2011 года, мне пришлось полностью закрыть мастер-машины в одном из моих двух AZ, следовательно, этот подход ...) – esilver