2012-05-30 3 views
2

Я пытаюсь создать очередь заданий с использованием двух главных серверов 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 

ответ

1

, что вы пытаетесь сделать, по сути, является мастер-мастер репликации, будь то очередь или что-нибудь еще, Redis не поддерживает его, и ваш псевдо-код имеет условия гонок. просто делает:

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

означает, другой работник может взять на себя работу в то время как вы делаете это, и две рабочие будут работать на него сразу. Я не думаю, что redis идеально подходит для вашего шаблона, и я не знаю сервера очередей, который может работать таким образом, но опять же, я не знаю многих таких серверов, поэтому я уверен, что есть.

Если вы загружаете баланс своей работы, так что только один мастер получает задание сразу, это возможно, но тогда у вас есть две очереди по существу, а не одна.

+0

SETNX возвращает сбой, если он не может получить блокировку, поэтому теоретически они оба потерпят неудачу, если они будут выполняться одновременно, а работа не будет выполнена, поэтому я думаю, что все будет хорошо (я полагаю, в одном случае, если бы только 1 задание в очереди. Я мог бы оказаться в ситуации, когда я не мог блокировать многократно, поэтому мне может потребоваться какой-то период отсрочки, но в реальном мире мои очереди будут переменной длиной, поэтому я сомневаюсь, что останусь в этом случае очень долго). Я знаю, что redis не поддерживает это, поэтому мне нужно сделать это на уровне приложений, так как машины EC2 и AZ могут и не работают ... – esilver

+0

, если один из клиентов сначала обратится к первому мастеру, а не к ближайшему мастеру действительно ли он отличается от цепной репликации (master-slave/master-slave)? –

+0

В моем фактическом коде клиент пытается связаться со своим ближайшим мастером (тот, который находится в его AZ), и если он не может, он отправится к мастеру в другой AZ. (FWIW во время Amazon Cloudpocalypse в апреле 2011 года, мне пришлось полностью закрыть мастер-машины в одном из моих двух AZ, следовательно, этот подход ...) – esilver

0

Мне любопытно ... если вы уже находитесь в среде AWS, почему бы вам не выбрать вместо этого сервис SQS Amazon? Я работал с ним в прошлом и понимаю, что это немного боль в заднице, но это самый зрелый сервис Amazon, и он предназначен для этого сценария.

+0

Из-за этого сообщения в блоге: https://github.com/blog/542-introducing-resque Цитата: «Мы были молодым сайтом и слышали истории на форумах Amazon с многоминутной задержкой между push и pop. То есть, однажды вы помещаете что-то в очередь, вы не сможете вернуть его за то, что может быть ненадолго. Это нас пугало, поэтому мы переехали ». Я также буду делать так много операций в очереди, что меня беспокоит, что это может стать дорогостоящим. Я в основном пытаюсь поставить в очередь все операции записи в RDS из-за его непредсказуемой латентности записи. – esilver

+0

LMAO ... хороший звонок. Даже не заставляйте меня НАЧАЛСЯ на латентность RDS.Я был сожжен этим. FYI, если латентность RDS - это то, что вас беспокоит, знайте, что mysql, работающий в старой школе (ака на реальном оборудовании), выкидывает дерьмо из RDS весь день. Когда мы бегали в проблемы с задержкой RDS, мы вытащили нашу базу данных mysql из облака и вернулись в облако только после переключения нашей системы на запуск cassandra и redis. – codemonkey

+0

Наш опыт прямо сейчас в том, что латентность RDS является супер-awesome (что очень мало), за исключением случаев, когда это не так. Фактически, после изучения еще нескольких, я решил продвинуться вперед с решением ASA Amazon и поставил 100% своих записей в RDS через SQS. Даже если на это потребуется несколько минут, чтобы вытащить что-то из очереди SQS, для нашей рабочей нагрузки это допустимо. – esilver

Смежные вопросы