Как заставить кластер запускать задачу только один раз?

13

Если бы у вас была задача, которую вы хотели бы выполнить только один раз на кластере серверов, через регулярные промежутки времени, что было бы лучшим способом достижения этого? В данном случае определение кластера - это два или более идентичных сервера с распределенными сеансами, расположенными за балансировщиком нагрузки.

Вариант использования: у вас есть задача, которая стоит дорого, и которую нужно запускать только один раз в X часов. Эта работа может, например, перебирать кучу записей и обновлять их статус.

  • В худшем случае, если задание будет выполнено дважды, ваши данные будут недействительными.
  • В лучшем случае сценарий использует ресурсы на всех ваших серверах.

Сводка требований:

  1. Задание все равно должно выполняться, даже если один из узлов не работает.
  2. Задание должно выполняться только один раз в соответствии с расписанием.
  3. Если несколько заданий запланировано одновременно или в одно и то же время, количество запущенных заданий распределяется поровну между серверами.
  4. Машины должны иметь одинаковую кодовую базу и синхронизироваться через NTP.
  5. Конфигурация может отличаться между узлами и узлами в зависимости от переменных среды.
  6. Задание должно начинаться вовремя или в течение заданного интервала назначенного времени. (скажем 5 минут например)

Возможные решения

  • Установите один узел как главный узел, это не работает, поскольку это нарушает 1 выше.
  • Сделайте запрос на балансировку нагрузки, чтобы начать работу. К сожалению, это имеет побочный эффект: если у вас одновременно запущено несколько заданий, все они могут выполняться на одной машине.

Это должно было бы работать на Java, в контейнере сервлета. Однако это не кодирование работы, которую я ищу.

Конечно, это решенная проблема с известным лучшим решением.


Смежный вопрос. /programming/5949038/schedule-job-executes-twice-on-cluster

Это не дубликат, поскольку решение является недостаточным в соответствии с этими 5 требованиями, приведенными выше. Решение с наибольшим количеством голосов страдает от проблемы гонки, а второе решение нарушает требование 3

Wes
источник

Ответы:

16

У вас есть общая база данных? Я сделал это, используя базу данных в качестве арбитра в прошлом.

По сути, каждое «задание» представляется в виде строки в базе данных. Вы планируете задание, добавляя строку в базу данных со временем, которое вы хотите запустить, после чего каждый сервер выполняет:

SELECT TOP 1 *
FROM jobs
WHERE state = 'NotRun'
ORDER BY run_time ASC

Таким образом, они все выберут работу, которая запланирована на следующую . Они все спят так, что просыпаются, когда на самом деле должна работать работа. Затем они все делают это:

UPDATE jobs
SET state = 'Running'
WHERE job_id = :id
  AND state = 'NotRun'

Где :idнаходится идентификатор работы, которую вы получили на шаге выше? Поскольку обновление является атомарным, только один из серверов будет фактически обновлять строку, вы можете проверить код состояния «количество обновлений строк» ​​базы данных, чтобы определить, был ли вы сервером, который фактически обновил строку, и, следовательно, являетесь ли вы сервером который получает работать.

Если вы не «выиграли» и не выполняете работу, просто немедленно вернитесь к шагу 1. Если вы «выиграли», запланируйте выполнение задания в другом потоке, затем подождите пару секунд, прежде чем вернуться к шагу 1. Таким образом, серверы, которые не получили задание в этот раз, с большей вероятностью получат задание. это запланировано запустить сразу.

Дин Хардинг
источник
1
Какой уровень изоляции вы используете здесь? Читать зафиксировано или сериализовать?
Маверик Риз
2

Некоторые серверы приложений имеют функцию «одноуровневых сервисов для всего кластера».

Например, в Weblogic есть функция Singleton Service, которая настраивается через консоль веб-администратора.

Вы должны написать класс, который реализует weblogic.cluster.singleton.SingletonService и использовать его для объявления службы в консоли администратора. Кластер заботится о создании экземпляра класса и уведомляет вас, когда служба запущена или остановлена. Интерфейс SingletonService имеет методы activ () и deactivate ().

Вызовы Weblogic активируют (), когда он впервые вызывает службу на одном из узлов кластера. Если выбранный узел выходит из строя, сервер администратора «перемещает» службу на другой сервер, вызывая там функцию activ ().

http://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/taskhelp/clusters/ConfigureSingletonService.html

Альфред Фалтиска
источник