Задачи Cron на балансированных нагрузках веб-серверах

Я ищу лучшее решение для обработки наших задач cron в сбалансированной нагрузке среде.

В настоящее время:

  • PHP-приложение, работающее на 3 CentOS-серверах за балансировщиком нагрузки.
  • Задачи, которые необходимо запускать периодически, но только на одной машине за раз.
  • Хороший старый cron, настроенный для запуска этих задач на первом сервере.
  • Проблемы, если первый сервер не работает по какой-либо причине.

Поиск:

  • Что-то более надежное и децентрализованное.
  • Загрузите балансировку задач, чтобы несколько задач запускались только один раз, но на случайных/разных серверах для распространения нагрузки.
  • Предотвращение выполнения задач при первом отключении сервера.
  • Возможность управлять задачами и просматривать сводные отчеты в идеале с помощью веб-интерфейса.
  • Уведомления, если что-то пойдет не так.

Решение не обязательно должно быть реализовано на PHP, но было бы неплохо, так как это позволило бы нам легко настроить его, если это необходимо.

Я нашел два проекта, которые выглядят обещаниями. GNUBatch и Планировщик заданий. Скорее всего, дальнейшие испытания обоих, но мне интересно, есть ли у кого-то лучшее решение для вышеперечисленного.

Спасибо.

Ответ 1

Вы можете использовать эту небольшую библиотеку, которая использует redis для создания временной временной блокировки:

https://github.com/AlexDisler/MutexLock

Серверы должны быть одинаковыми и иметь одну и ту же конфигурацию cron. Сервер, который будет первым создавать блокировку, также выполнит задачу. Другие серверы будут видеть блокировку и выход без каких-либо действий.

Например, в php файле, который выполняет запланированную задачу:

MutexLock\Lock::init([
  'host'   => $redisHost,
  'port'   => $redisPort
]);

// check if a lock was already created,
// if it was, it means that another server is already executing this task
if (!MutexLock\Lock::set($lockKeyName, $lockTimeInSeconds)) {
  return;
}

// if no lock was created, execute the scheduled task
scheduledTaskThatRunsOnlyOnce();

Чтобы выполнить задачи децентрализованным способом и распространить нагрузку, посмотрите: https://github.com/chrisboulton/php-resque Это php-порт рубиновой версии resque и сохраняет данные в том же точном формате, чтобы вы могли использовать https://github.com/resque/resque-web или http://resqueboard.kamisama.me/ для мониторинга рабочих и просмотра отчетов

Ответ 2

Предполагая, что у вас есть база данных, не размещенная на одном из этих трех серверов;

Напишите "обертку" script, которая идет в cron, и берет программу, которую вы запускаете, в качестве аргумента. Самое первое, что он делает, это подключиться к удаленной базе данных и проверить, когда последний раз, когда запись была вставлена ​​в таблицу (созданная для этой обертки). Если последнее время вставки больше, чем когда оно должно было запускаться, вставьте новую запись в таблицу с текущим временем и выполните аргумент оболочки (ваше задание cron).

Cron вверх по обертке на каждом сервере, каждый набор за X минут позади другого (сервер A работает в верхней части часа, сервер B работает через 5 минут, C через 10 минут и т.д.).

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

Если вы также записываете в таблице, на каком сервере выполнялось задание, вы будете иметь журнал о том, когда/где был выполнен script.

Ответ 3

Разве это не идеальная ситуация для использования очереди сообщений/задач?