10

Эй. Я использую delayed_job для фоновой обработки. У меня 8 ЦП сервера, MySQL и начинаю 7 delayed_job процессыРельсы, выполняющие несколько замедленных_записей - блокировки столов

RAILS_ENV=production script/delayed_job -n 7 start 

Q1: Я интересно, возможно ли, что 2 или более delayed_job процессы начать обработку того же процесса (один и тот же рекорд-строку в база данных delayed_jobs). Я проверил код плагина delayed_job, но не могу найти директиву блокировки так, как это должно быть (таблица блокировки или SELECT ... FOR UPDATE).

Я думаю, что каждый процесс должен блокировать таблицу базы данных перед выполнением UPDATE в столбце lock_by. Они блокируют запись, просто обновив поле locked_by (UPDATE delayed_jobs SET locked_by ...). Это действительно достаточно? Не требуется блокировка? Зачем? Я знаю, что UPDATE имеет более высокий приоритет, чем SELECT, но я думаю, что это не имеет эффекта в этом случае.

Моего понимания многоковшовой нарезкой ситуации на это:

Process1: Get waiting job X. [OK] 
Process2: Get waiting jobs X. [OK] 
Process1: Update locked_by field. [OK] 
Process2: Update locked_by field. [OK] 
Process1: Get waiting job X. [Already processed] 
Process2: Get waiting jobs X. [Already processed] 

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

Q2: Есть 7 delayed_jobs хорошее количество для сервера 8CPU? Почему да/нет.

Thx 10x!

ответ

11

Я думаю, что ответ на ваш вопрос находится в строке 168 «Lib/delayed_job/job.rb»:

self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?)", id, (now - max_run_time.to_i)]) 

Здесь обновление строки выполняется только, если никакой другой работник не уже заблокирован задание, и это проверяется, если таблица обновлена. Блокировка таблицы или подобное (что, кстати, значительно уменьшало производительность вашего приложения) не требуется, так как ваша СУБД гарантирует, что выполнение одного запроса изолировано от эффектов от других запросов. В вашем примере Process2 не может получить блокировку для задания X, поскольку он обновляет таблицу заданий тогда и только тогда, когда она не была заблокирована раньше.

К вашему второму вопросу: Это зависит. На сервере с 8 процессорами. которая посвящена этой работе, 8 рабочих являются хорошей отправной точкой, так как рабочие однопоточные, вы должны запускать один для каждого ядра. В зависимости от вашей установки более или менее рабочие лучше. Это зависит от ваших рабочих мест. Воспользуйтесь преимуществами работы нескольких ядер? Или ваша работа больше всего ждет внешних ресурсов? Вы экспериментируете с различными настройками и смотрите на все задействованные ресурсы.

+0

Итак, вы говорите, что каждый процесс является процессом в стиле атома и безопасен? – xpepermint

+0

Я думаю, что здесь отсутствует SELECT ... FOR UPDATE. ? – xpepermint

+0

Запрос является атомарным. Следовательно, если вы выполняете запрос 'UPDATE jobs SET locked_at = '..', locked_by = 1 WHERE id = 12 и (locked_at имеет значение null или locked_at <'..')', то locked_at и locked_by обновляются только в том случае, если нет другой действующий блокировка. СУБД сначала проверяет, где условие затем выполняет обновление, и гарантирует, что строка не будет изменяться между ними. Следовательно, вы не можете перезаписать существующий замок. – gregor