1. Основной принцип реализации кварцевого планирования задач
Quartz - это проект с открытым исходным кодом в области планирования задач с помощью OpenSymphony, которая полностью основана на реализации Java. В качестве отличной структуры планирования с открытым исходным кодом, Quartz имеет следующие функции:
(1) мощные функции планирования, такие как поддержка различных методов планирования, могут удовлетворить различные обычные и особые потребности;
(2) гибкие методы применения, такие как поддержка нескольких комбинаций задач и планирования, а также поддержка нескольких методов хранения данных планирования;
(3) Распределенные и кластеризационные возможности, TerraCotta еще больше улучшила свои первоначальные функции после приобретения. Эта статья будет добавлена к этой части.
1.1 Кварц -основные элементы
Основными элементами планирования задач кварца являются: планировщик планировщика планировщика, триггер-триггер и задача задания. где триггер и задание являются метаданными для планирования задач, а планировщик - это контроллер, который фактически выполняет планирование.
Триггер - это элемент, используемый для определения времени планирования, то есть в соответствии с правилами времени выполняется задача. В Quartz есть четыре типа триггеров: Simplytrigger, Crontirgger, DateIntervaltrigger и nthincluddayTrigger. Эти четыре триггера могут удовлетворить большинство потребностей предприятий.
Работа используется для представления запланированных задач. В основном есть два типа рабочих мест: без гражданства и государства. Для того же триггера рабочие места состояния не могут быть выполнены параллельно. Только после того, как заработанная задача выполнена последняя, может быть вызвано следующее выполнение. У задания есть два основных атрибута: летучая и долговечность, когда летучие означает, сохраняется ли задача для хранения базы данных, в то время как долговечность означает, сохраняется ли задача, когда нет триггерных ассоциаций. Оба сохраняются или сохранились, когда значение верно. Работа может быть связана с несколькими триггерами, но триггер может связать только одну работу.
Планировщик создается заводской фабрикой Scheduler: DirectSchedulerFactory или StdschedulerFactory. Вторая фабрика, StdschedulerFactory, используется чаще, потому что DirectSchedulerFactory недостаточно удобен для использования, и требуются многие подробные настройки ручного кодирования. Существует три основных типа планировщика: remotembeanscheduler, remotscheduler и stdscheduler.
Связь между основными элементами кварца показана на рисунке 1.1:
Рисунок 1.1 Диаграмма отношения основного элемента элемента
1.2 View Quartz Thread
В кварце есть два типа потоков, потоки планировщика планировщика и потоки выполнения задач, где потоки выполнения задач обычно используют пул потоков для поддержания группы потоков.
Рисунок 1.2 Вид кварцевого потока
Есть два основных потока для планировщика: потоки, которые выполняют регулярное планирование и потоки, которые выполняют MisfiredTrigger. Регулярные опросы в диспетчерской нити хранятся все триггеры. Если есть триггер, который необходимо запустить, то есть время следующего триггера достигнут, он получает поток холостого хода из пула потоков выполнения задачи для выполнения задачи, связанной с триггером. Нить пропуски сканирует все триггеры, чтобы увидеть, есть ли осадок. Если это так, это обрабатывается отдельно в соответствии с политикой окармливания (пожар сейчас или ждите следующего пожара).
1.3 Кварц
Триггеры и рабочие места в кварце должны храниться, прежде чем их можно будет использовать. В Quartz есть два метода хранения: Ramjobstore и JobSoresOpport, где Ramjobstore магазины триггеры и задания в памяти, в то время как магазины JobSoresOpport триггеры и задания в базе данных на основе JDBC. Ramjobstore - очень быстрый доступ, но, поскольку все данные будут потеряны после остановки системы, JobSorSorePport должен использоваться в приложениях кластера.
2. Принцип кварцевого кластера 2.1 Кварцевая кластерная архитектура
Каждый узел в кварцевом кластере является независимым кварцевым приложением, которое, в свою очередь, управляет другими узлами. Это означает, что вы должны начать или остановить каждый узел отдельно. В кварцевом кластере независимые кварцевые узлы не общаются с другим узлом или узлом управления, а вместо этого воспринимают другое кварцевое приложение через ту же таблицу базы данных, как показано на рисунке 2.1.
Рисунок 2.1 Кварцевая кластерная архитектура
2,2 Таблицы баз данных, связанные с кварцевым кластером
Поскольку кварцевый кластер зависит от базы данных, необходимо сначала создать таблицу базы данных кварц. Пакет выпуска Quartz включает в себя сценарии SQL для всех поддерживаемых платформ баз данных. Эти сценарии SQL хранятся в каталоге <Quartz_home>/Docs/dbtables. Кварцевая версия 1.8.4, используемая здесь, имеет в общей сложности 12 таблиц. Количество таблиц может отличаться в разных версиях. База данных - MySQL, и используйте tables_mysql.sql для создания таблицы базы данных. Все таблицы показаны на рисунке 2.2, а краткое введение в эти таблицы показано на рисунке 2.3.
Рисунок 2.2 Таблицы, сгенерированные в кварце 1.8.4 в базе данных MySQL
Рисунок 2.3 Введение в таблицу данных кварца
2.2.1 Таблица состояния планировщика (QRTZ_SCHEDULER_STATE)
Описание.
exance_name: имя, настроенное на org.quartz.scheduler.instanceid в файле конфигурации. Если установлено в Auto, Quartz будет генерировать имя на основе имени физической машины и текущего времени.
last_checkin_time: последнее время регистрации
checkin_interval: время регистрации
2.2.2 Таблица ассоциации триггера и задач (qrtz_fired_triggers)
Хранит информацию о состоянии, связанную с запускаемой информацией о триггере и выполнении соответствующей задачи.
2.2.3 Таблица информации о запусках (QRTZ_TRIGGERS)
trigger_name: имя триггера, пользователь может настроить имя по желанию, без принудительных требований
trigger_group: имя группы триггеров, которую пользователь может настроить по желанию, и не существует вынужденных требований.
job_name: иностранный ключ из QRTZ_JOB_DETAILS TABLE JOB_NAME
job_group: qrtz_job_details table job_group иностранная ключ
trigger_state: текущее состояние триггера установлено на приобретение. Если он настроен на ожидание, задание не запускается.
trigger_cron: тип триггера, используя выражение Cron
2.2.4 Таблица сведений о задачах (QRTZ_JOB_DETAILS)
Примечание. Сохраните данные задания, таблица должна быть инициализирована пользователем в соответствии с фактической ситуацией
job_name: имя работы в кластере. Пользователь может настроить имя по желанию без каких -либо принудительных требований.
job_group: имя группы, которой принадлежит задание в кластере, которая настроена пользователем по желанию, и не существует вынужденных требований.
job_class_name: полное имя пакета класса реализации задания в кластере. Кварц находит класс работы, основанный на этом пути к классу.
IS_DILLEAL: Будь то сохранить, установите это свойство на 1, Кварц сохранит задание в базе данных
job_data: поле Blob, которое хранит, сохраняло объекты работы.
2.2.5 Таблица информации о разрешении (qrtz_locks)
ПРИМЕЧАНИЕ. Существует соответствующая инициализация DML в tables_oracle.sql, как показано на рисунке 2.4.
Рисунок 2.4 Информация об инициализации в таблице информации о разрешении кварца
2.3 Процесс запуска кварцевого планировщика в кластере
Сам планировщик Quartz не замечает, что он кластеризован, и только JDBC Jobstore, настроенный для планировщика. Когда запускается Quartz Scheduler, он вызывает метод PradeLestarted () JobStore, который сообщает планировщику Jobstore, что он начал. Метод PradeLeStared () реализован в классе JobSorSorePport. Класс JobSorSorePport определяет, участвует ли экземпляр планировщика в кластере на основе настройки в файле Quartz.properties. Если кластер настроен, будет создан экземпляр нового класса ClusterManager, инициализируется и запускается. ClusterManager-это встроенный класс в классе JobSorSorePport, наследует Java.lang.thread, он регулярно работает и выполняет функции регистрации в экземпляре планировщика. Планировщик также должен проверить, не удались ли какие -либо другие кластерные узлы. Цикл выполнения операции регистрации настроен в Quartz.properties.
2.4 Обнаружение неисправного узла планировщика
Когда экземпляр планировщика выполняет регистрацию, он проверяет, не были ли другие экземпляры планировщика не были зарегистрированы в то время, когда они ожидали. Это определяется путем проверки того, является ли значение планировщика, записанного в столбце последнего_CHEDK_TIME в таблице Scheduler_state раньше, чем org.quartz.jobstore.clusterCheckinInterval. Если один или несколько узлов не были зарегистрированы в заранее определенное время, то работающий планировщик предполагает, что он потерпел неудачу.
2.5 Восстановление заданий из неудачных экземпляров
Когда экземпляр Sheduler выходит из строя при выполнении задания, возможно, что другой экземпляр рабочего планировщика возьмет на себя задание и запустит ее снова. Для достижения такого поведения свойство восстановления задания, настроенное на объект JobDetail, должно быть установлено на true (job.setRequestsRecovery (true)). Если восстанавливаемое свойство установлено на false (по умолчанию неверно), оно не будет повторно, когда планировщик не сможет запустить задание; Это будет вызвано другим экземпляром планировщика в следующее время триггера. Насколько быстро экземпляр планировщика может быть обнаружен после сбоя, зависит от интервала регистрации каждого планировщика (то есть org.quartz.jobstore.clustercheckininterval, упомянутый в 2.3).
3. экземпляр Quartz Cluster (Quartz+Spring)
3.1 пружина несовместима с кварцами.
Весна больше не поддерживает кварц с 2.0.2. В частности, когда Quartz+Spring создает задачу Quartz в базе данных, произойдет последовательная ошибка:
<bean id = "jobtask"> <name = "targetObject"> <ref bean = "quartzjob"/> </property> <name = "targetMethod"> <dure> execute </value> </property> </bean>
Метод MethodInvoking в классе MethodInVokingJobdetailFactorybean не поддерживает сериализацию, поэтому он принесет ошибку при сериализации задачи кварца в базу данных.
Во -первых, решить проблему метода invokingjobdetailfactorybean. Без изменения исходного кода Spring вы можете избежать использования этого класса и напрямую вызовать JobDetail. Тем не менее, использование реализации JobDetail требует от вас самостоятельной внедрения логики мотодинвока. Вы можете использовать свойства JobClass и JobDataAsmap of JobDetail для настройки фабрики (менеджера) для достижения той же цели. Например, в этом примере создается новый MyDetailQuartzJobbean для реализации этой функции.
3.2 MyDetailQuartzjobbean.java файл
пакет org.lxh.mvc.jobbean; import java.lang.reflect.method; import org.apache.commons.logging.log; import org.apache.commons.logging.logfactory; import org.quartz.jobexecutioncontext; импорт org.quartz.jobexecureTexcretexcret; org.springframework.context.applicationContext; import org.springframework.scheduling.quartz.quartzjobbean; открытый класс mydetailquartzjobbean quartzjobbean {protected final logger = logfactory.getlog (getClass ()); частная строка TargetObject; частная строка TargetMethod; Private ApplicationContext CTX; Protected void executeInternal (context jobExecutionContext) Throws JobExeCutionException {try {logger.info ("execute [" + targetObject + "] сразу >>>>>"); Object OargetObject = ctx.getBean (TargetObject); Метод m = null; try {m = oargetObject.getClass (). getMethod (targetMethod, новый класс [] {}); m.invoke (OargetObject, новый объект [] {}); } catch (securityException e) {logger.error (e); } catch (nosuchmethodexception e) {logger.error (e); }} catch (Exception e) {бросить новый JobExecutionException (e); }} public void setApplicationContext (ApplicationContext ApplicationContext) {this.ctx = ApplicationContext; } public void setargetObject (string targetObject) {this.TargetObject = targetObject; } public void SetTargetMethod (String TargetMethod) {this.TargetMethod = targetMethod; }}3.3 Настоящий класс реализации работы
В тестовом классе функция печати текущего времени системы просто реализована.
Пакет org.lxh.mvc.job; import java.io.serializable; import java.util.date; import org.apache.commons.logging.log; import org.apache.commons.logging.logfactory; public class test extuments serializable {private logger = logfactory.getgleg (test.class); Частный статический последний длинный серийный режим = -20733105864997444415L; public void execute () {date = new Date (); System.out.println (date.tolocalestring ()); }}3.4 Настройте файл Quartz.xml
<bean id="Test" scope="prototype"> </bean> <bean id="TestjobTask"> <property name="jobClass"><value>org.lxh.mvc.jobbean.MyDetailQuartzJobBean</value> </property> <property name="jobDataAsMap"> <map> <entry key="targetObject" value="Test" /> <entry key = "targetMethod" value = "execute"/> </map> </property> </bean> <bean name = "testtrigger"> <name = "jobdetail" ref = "testjobtask"/> <name = "cronexpression" value = "0/1 * * *?" /> </bean> <bean id = "quartzscheduler"> <name = "configlocation" value = "classpath: quartz.properties"/> <name = "triggers"> <sist> <ref bean = "testtrigger"/> </list> </propetion> <proportce name = "ApplicationContextSchedulUrercelectextextekekek
3.5 Тест
Код и конфигурация Servera и ServerB точно такие же. Сначала запустите Servera, а затем запустите Serverb. После того, как сервер будет выключен, ServerB будет отслеживать его выключение и захватить задание, выполняемое на Servera, и продолжить выполнение.
4. экземпляр Quartz Cluster (один кварц)
Хотя мы реализовали конфигурацию кластера пружины+кварц, все еще не рекомендуется использовать этот метод из -за проблем совместимости между пружиной и кварцем. В этом разделе мы реализовали кластер, настроенный отдельно с помощью кварца, который является простым и стабильным по сравнению с пружиной+кварцем.
4.1 Инженерная структура
Мы используем только Quartz для реализации его функций кластера, структуры кода и необходимых сторонних пакетов JAR, как показано на рисунке 3.1. Среди них версия MySQL: 5.1.52, и версия драйвера MySQL: MySQL-Connector-Java-5.1.5-bin.jar (для 5.1.52 рекомендуется использовать эту версию драйвера, потому что в кварце есть ошибка, которая не может нормально работать при сочетании с некоторыми драйверами MySQL).
Рисунок 4.1 Кварц-кластерная конструкция и необходимые сторонние пакеты JAR
Среди них quartz.properties - файл конфигурации кварца и размещен в каталоге SRC. Если такого файла нет, Quartz автоматически загрузит файл Quartz.properties в пакет JAR; SimpleEcoveryJob.java и SimpleERecoveryStatefuljob.java - две задания; ClusterExample.java записывает информацию о планировании, механизм запуска и соответствующие тестовые основные функции.
4.2 Configuration File Quartz.properties
Имя файла по умолчанию quartz.properties используется для активации функции кластера, установив «свойство org.quartz.jobstore.isclustered» для «true». Каждый экземпляр в кластере должен иметь уникальное «идентификатор экземпляра» («org.quartz.scheduler.instanceid»), но оно должно иметь одинаковое «имя экземпляра планировщика» («org.quartz.scheduler.instancename»), что означает, что каждый экземпляр в одном и том же файле конфигурации Quartz.Properties. За исключением следующих исключений, содержимое файла конфигурации должно быть одинаковым:
а Размер бассейна.
беременный Различные "org.quartz.scheduler.instanceId" значения атрибутов (просто установлены на "Auto").
#==================================================================== ======================================================================= ======================================================================= ======================================================================= ======================================================================= ======================================================================= ======================================================================= ======================================================================= Auto#========================================================================================================= ========================================================================================== org.quartz.jobstore.impl.jdbcjobstore.jobstoretxorg.quartz.jobstore.driverdelegateclass = org.quartz.impl.jdbcjobstore.stdjdbcdelegateorg.quartz.jobstore.tableprefix = Qrtz_org.quartz.jobstore.isclustered = trueorg.quartz.jobstore.clustercheckininterval = 10000 org.quartz.jobstore.datasource = myds #========================================================================================== ========================================================================================== ========================================================================================== ========================================================================================== #===================================================================================================== com.mysql.jdbc.driverorg.quartz.datasource.myds.url = jdbc: mysql: //192.168.31.18: 3306/test? useunicode = true & charcyencoding = utf-8org.quartz.datasource.myds.user = rootcortzarg.dapashry.dapashras. 123456org.quartz.datasource.myds.maxconnections = 30#================================================================== ===================================================================== ===================================================================== ===================================================================== ===================================================================== ===================================================================== ===================================================================== ===================================================================== org.quartz.simpl.simplethreadpoolorg.quartz.threadpool.threadcount = 5org.quartz.threadpool.threadpriority = 5org.quartz.threadpool.threadsinheritcontextclasslofinitialithread = true
4.3 clusterExample.java файл
Кластер пакетов; импорт java.util.date; import org.quartz.jobdetail; import org.quartz.scheduler; import org.quartz.schedulerfactory; import org.quartz.simpletrigger; import org.quartz.ImpleCedScheduleryRectory; Exception {System.out.println ("**** Удаление существующих заданий/триггеров *****"); // unscedule заданий string [] groups = inscheduler.getTriggerGroupNames (); for (int i = 0; i <groups.length; i ++) {string [] names = inscheduler.getTriggerNames (группы [i]); for (int j = 0; j <names.length; j ++) {inscheduler.unschedulejob (names [j], группы [i]); }} // Удалить задания Groups = inscheduler.getJobGroupNames (); for (int i = 0; i <groups.length; i ++) {string [] names = inscheduler.getJobNames (группы [i]); for (int j = 0; j <names.length; j ++) {inscheduler.deletejob (names [j], группы [i]); }}} public void run (boolean inclearjobs, boolean inschedulejobs) бросает исключение {// Сначала мы должны получить ссылку на планировщик SchedulerFactory sf = new StdschedulerFactory (); Scheduler share = sf.getscheduler (); if (intearjobs) {learup (share); } System.out.println ("-------------------------------"); if (inschedulejobs) { System.out.println("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Повторно представьте эту работу, если она была в процессе, когда // планировалось ... " + Trigger.getNextFireTime () +" и повторение: " + trigger.getRepeatCount () +" times, каждый " + trigger.getRepeatInterval () / 1000 +" секунды "); chady.schedulejob (job, trigger); count ++; job = jobdetail (" job_ + counte, wardid -storftor Планировщик, чтобы повторно рассказать об этой работе, если она была в процессе работы, когда // планировалось ... at: « + trigger.getNextFireTime () +» и «Повторите»: « + trigger.getRepeatCount () +« время, каждый " + trigger.getRepeatInterval () / 1000 +" Секунды "); ched.schedulejob (job, trigger);} // задания не запускаются до начала (). System.out.println ("-------------------------------------"); System.out.println("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Thread.sleep(3600L * 1000L); System.out.println ("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- args.length; }}4.4 SimpleEcoveryJob.java
Кластер пакетов; импорт java.io.serializable; import java.util.date; import org.apache.commons.logging.log; import org.apache.commons.logging.logfactory; импорт org.quartz.job; импорт org.quartz.jobexectuctontext; Чтобы выполнить многократно, запишите соответствующий код в методе выполнения, предпосылка: реализовать интерфейс задания // Что касается того, когда класс SimpleJob создается и когда называется метод выполнения, нам не нужно обращать на него внимание, и оставлять его в Quartzpublic Class SimpleErecoveryJob job job, serializable {private static _log gogfactory. public simpleEcoveryjob () {} public void Execute (jobExecutyContext context) Throws JobExeCuteException {// Это задание просто распечатает имя задания и время, когда задание использует string jobName = context.getJobdetail (). getFullName (); System.out.println ("Job 1111111111111111" SimpleErecoveryJob говорит: " + jobname +" Выполнение в " + new Date ()); }}4.5 Результаты работы
Конфигурация и код на сервере A и сервере B точно такие же. Запуск метода: запустите ClusterExample.java на любом хосте, добавьте задачу в расписание и соблюдайте результаты запуска:
Запустите Servera, результаты показаны на рисунке 4.2.
Рисунок 4.2 Результат работы сервера 1 Результат 1
После включения ServerB вывод Servera и ServerB показан на рисунках 4.3 и 4.4.
Рисунок 4.3. Результат работы Servera 2
Рисунок 4.4 Результат работы сервера 1 Результат 1
Из рисунков 4.3 и 4.4 видно, что после включения ServerB система автоматически реализует ответственность за баланс, а ServerB берет на себя job1. После выключения Servera результаты работы ServerB показаны на рисунке 4.5.
Рисунок 4.5 Результат работы сервера 2 Результат 2
Как видно из рисунка 4.5, ServerB может обнаружить, что Servera потерян, взять на себя задачу job2 и потерять Servera в JOB2, который необходимо выполнить в течение этого исключения.
5. Что следует отметить
5.1 Проблема синхронизации времени
Кварц на самом деле не заботится о том, запускаете ли вы узлы на одних и тех же или разных машинах. Когда кластер помещается на разные машины, он называется горизонтальным кластером. Когда узел работает на одной машине, он называется вертикальным кластером. Для вертикальных кластеров существует проблема единой точки отказа. Это неприемлемо для приложений с высокой доступностью, потому что после сбоя машины все узлы прекращаются. Для горизонтальных кластеров существует проблема синхронизации времени.
Узел использует временную метку, чтобы уведомить другие экземпляры собственного последнего времени регистрации. Если часы узла будут установлены в будущее, работающий планировщик больше не поймет, что узел упал. С другой стороны, если часы узла устанавливаются на прошлое время, возможно, другой узел определит, что узел выпал и попытается взять свою работу и повторить. Самый простой способ синхронизировать компьютерные часы - это использовать интернет -сервер времени.
5.2 Проблема узлов, конкурирующих за рабочие места
Поскольку Quartz использует алгоритм балансировки случайной нагрузки, задание выполняется в разных случаях случайным образом. Официальный веб -сайт Quartz упомянул, что в настоящее время не существует метода назначения (PIN) задания определенному узлу в кластере.
5.3 Выпуск для получения списка работы от кластера
В настоящее время, если вы не вводите запрос базы данных напрямую, нет простого способа получить список всех выполняющихся заданий в кластере. Запрашивание экземпляра планировщика получит только список заданий, работающих в этом экземпляре. Официальный веб -сайт Quartz рекомендует получить всю информацию о работе из соответствующей таблицы, написав немного кода JDBC для доступа к базе данных.
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.