Как изящно справиться с тысячами осечек Quartz?

У нас есть приложение, которое должно

  1. каждую ночь обрабатывать большие объемы данных и

  2. повторно обрабатывать большие объемы данных по запросу.

В обоих этих случаях создается и затем запускается около 10 000 кварцевых заданий. В случае nightly у нас есть одно задание кварца cron, которое порождает 10 000 заданий, каждое из которых по отдельности выполняет работу по обработке данных.

Проблема заключается в том, что мы работаем с примерно 30 потоками, поэтому, естественно, задания кварца дают осечку и продолжают сбоить, пока все не будет обработано. Обработка может занять до 6 часов. Каждое из этих 10 000 заданий относится к определенному объекту домена, который может обрабатываться параллельно и является полностью независимым. Каждое из 10 000 заданий может занять разное время (от полсекунды до минуты).

Мой вопрос:

  1. Есть лучший способ сделать это?

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

Примечание об архитектуре: мы используем два кластера с тремя узлами в каждом. Версия кварца немного устарела (2.0.1), а кластеризация включена в файле кварца.свойства.


person Brett McLain    schedule 27.12.2013    source источник
comment
Нет ли способа равномерно распределить нагрузку в течение дня? (например, очереди)   -  person Sami Korhonen    schedule 27.12.2013
comment
Для ночных мы можем сделать это, но для по требованию это должно выполняться как можно быстрее. Одна из моих мыслей заключалась в том, чтобы просуммировать количество создаваемых заданий кварца и взять среднее время выполнения одного потока, а затем соответственно случайным образом запланировать задания кварца, также учитывая количество потоков. Это помогло бы немного смягчить осечки, но время выполнения одного потока слишком изменчиво, и всегда предполагается, что наихудший сценарий займет слишком много времени в случае обработки по запросу.   -  person Brett McLain    schedule 27.12.2013
comment
Я думаю, что использовать Quartz для такого сценария неправильно, поскольку все задания, которые вы создаете, должны выполняться немедленно, а не в определенное время. Как и в других ответах, предлагается использовать очереди, и здесь наиболее целесообразно использовать службу-исполнитель.   -  person Leonard Brünings    schedule 30.12.2013


Ответы (4)


В обоих этих случаях создается около 10 000 кварцевых заданий.

Нет необходимости создавать новые задания кварца. Кварц — это планировщик, а не диспетчер задач.

При ночной обработке вам нужно только это одно кварцевое cron задание, чтобы вызвать какую-либо службу, отвечающую за управление и выполнение 10 000 задач. В сценарии «по требованию» кварц вообще не должен использоваться. Просто вызовите эту службу напрямую.

Как служба справляется с 10 000 задач?

Как правило, когда доступна только одна JVM, вы просто используете несколько ExecutorService. Здесь, поскольку у вас под рукой 6 узлов, вы можете легко использовать Hazelcast. Hazelcast — это библиотека Java, которая позволяет вам кластеризовать узлы, эффективно разделяя ресурсы друг с другом. У Hazelcast есть простое решение для распространения вашего ExecutorService, которое называется Distributed Executor Service. . Это так же просто, как создать Hazelcast ExecutorService и отправить задачу всем участникам. Вот пример из документации для вызова одного члена:

Callable<String> task = new Echo(input); // Echo is just some Callable
HazelcastInstance hz = Hazelcast.newHazelcastInstance();
IExecutorService executorService = hz.getExecutorService("default");
Future<String> future = executorService.submitToMember(task, member);
String echoResult = future.get();
person yair    schedule 30.12.2013

Я бы сделал это, используя очередь (RabbitMQ/ActiveMQ). Задание cron (или любой другой триггер по запросу) заполняет очередь сообщениями, представляющими 10 000 рабочих инструкций (т. е. инструкции по повторной обработке данных для данного объекта домена).

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

person azordi    schedule 30.12.2013

Лучший способ — использовать кластер экземпляров Quartz. Это позволит разделить задания между многими узлами кластера: http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJDBCJobStoreClustering

person Ali HAMDI    schedule 27.12.2013
comment
На самом деле это плохая идея, так как кварцу пришлось бы много раз обращаться к JDBCStore (=базе данных). И поскольку OP добавлен в EDIT, опция кластера уже используется. - person yair; 30.12.2013

Я бы использовал запланированное задание кварца, чтобы инициировать задачи 10 000, но это делается путем добавления сведений о задаче в очередь JMS (сообщения 10 000). Эта очередь контролируется компонентом, управляемым сообщениями (Java-EE EJB MDB). MDB может работать одновременно на нескольких узлах в вашем кластере, и каждый узел может запускать несколько экземпляров... не изобретайте велосипед для распределенной нагрузки: пусть это сделает Java-EE.

person Glenn Lane    schedule 01.01.2014