Обработка большого количества задач при помощи delayed_job

в 15:41, , рубрики: resque, ruby on rails, метки: ,

Я большой фанат resque, который использует Redis в качестве хранилища, однако если есть необходимость быстро выполнить большое количество фоновых задач, в некоторых случаях delayed_job может работать более эффективно благодаря тому, что он не вызывает fork() каждый раз при выполнении новой задачи.

fork() в Linux достаточно медленная операция несмотря на все прелести Copy on Write. В случае выполнения большого количества однородных задач нет никакого смысла порождать новый процесс для выполнения каждой задачи. Поэтому мы решили использовать delayed_job, который выполняет все задачи в одном цикле последовательно друг за другом.

Преимущество понятно, попробую здесь изложить несколько подсказок как можно устранить недостатки тем самым ускорив выполнение. Я думаю, что это достаточно общеизвестные факты, но новичкам должно быть полезно.

Оборачивайте много INSERT в одну транзакцию

delayed_job делает вставку в таблицу delayed_jobs каждый раз, когда добавляется новая задача.

В ActiveRecord вызовы save по-умолчанию оборачиваются в транзакцию. Поэтому, чтобы не получить огромное количество транзакций при массовом создании фоновых задач, рекомендуется оборачивать всё в одну или несколько транзакций:

job_items.in_groups_of(500, false) do |group|
  ActiveRecord::Base.transaction do
    group.each do |job_item_id|
      JobRunner.delay.execute_job(job_item_id)
    end
  end
end

Подробнее здесь: www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/

Избегайте накладных расходов на сериализацию/десериализацию

delayed_job сериализует данные, когда создаёт задачу и десериализует непосредственно перед выполнением. В качестве параметров для фоновых задач всегда лучше передавать объекты класса Fixnum, String или Hash вместо тяжёлых ActiveRecord объектов.

JobRunner.delay.send_activation_instructions(user.id)

Гораздо лучше чем:

JobRunner.delay.send_activation_instructions(user)

Запускайте воркеры delayed_job по количеству ядер

Многопоточность в Ruby оставляет желать лучшего, поэтому обычно всё распараллеливается при помощи создания нескольких процессов.

Не исключение и delayed_job. К примеру, если у вас top / htop показывает 4 потока, то для достижения наилучшей производительности нужно запускать 4 воркера:

script/delayed_job -i 0 start
script/delayed_job -i 1 start
script/delayed_job -i 2 start
script/delayed_job -i 3 start

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

Кстати, в delayed_job есть конфигурация для мониторинга нескольких воркеров с помощью monit (см. файл contrib/delayed_job_multiple.monitrc).

Дополнительно

Так же, стоит обратить внимание на следующие дополнения:

Стоит отметить, что delayed_job_redis нам так и не удалось запустить с Rails 3.2.

Автор: akhkharu

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js