Turn yourself Jane books blog www.jianshu.com/p/498c662e9…

The background,

So far, quartz cluster mode can only be used if the storage mode is enabled. I use mysql database for storage. Because I like to see the source code from multidimensional analysis, today I hope to understand the startup process of Quartz cluster environment by combining mysql-binlog; Mysql > enable binlog

Because binlog is turned off by default; This can be done by modifying the my.ini file. There is a simple configuration that takes only one parameter

log-bin=/var/lib/mysql/mysql-bin

You can also search how to enable binlog; Binlog records only the NEWLY added, modified, and deleted SQL statements. Start Quartz and view binlog

After stopping a Quartz node for a period of time (3 minutes in this case) and restarting the Quartz node, I want to export some binlogs to see what changes have been made. Because binlog logs are binary files and cannot be read directly, you can use the mysqlbinlog tool in the mysql/bin/ directory to export binlog logs.

./mysqlbinlog .. 000001 > / logs/mysql – bin. D: / binlog. TXT.

Mysql > select binlog.txt from binlog.txt

# at 347638 #181017 9:07:05 server id 1 end_log_pos 347870 Query thread_id=18 exec_time=0 error_code=0 SET TIMESTAMP=1539738425/*! * /. UPDATE JOB_QRTZ_SCHEDULER_STATE SET LAST_CHECKIN_TIME = 1539738425978 WHERE SCHED_NAME = 'schedulerFactoryBean' AND INSTANCE_NAME = 'DESKTOP-7U74VP91539738404656' /*! * /. # at 347870 #181017 9:07:05 server id 1 end_log_pos 348128 Query thread_id=18 exec_time=0 error_code=0 SET TIMESTAMP=1539738425/*! * /. INSERT INTO JOB_QRTZ_SCHEDULER_STATE (SCHED_NAME, INSTANCE_NAME, LAST_CHECKIN_TIME, CHECKIN_INTERVAL) VALUES('schedulerFactoryBean', 'DESKTOP-7U74VP91539738404656', 1539738425978, 5000000) /*! * /. # at 348128 #181017 9:07:05 server id 1 end_log_pos 348326 Query thread_id=18 exec_time=0 error_code=0 SET TIMESTAMP=1539738425/*! * /. DELETE FROM JOB_QRTZ_FIRED_TRIGGERS WHERE SCHED_NAME = 'schedulerFactoryBean' AND INSTANCE_NAME = 'DESKTOP-7U74VP91539681653705' /*! * /. # at 348326 #181017 9:07:05 server id 1 end_log_pos 348525 Query thread_id=18 exec_time=0 error_code=0 SET TIMESTAMP=1539738425/*! * /. DELETE FROM JOB_QRTZ_SCHEDULER_STATE WHERE SCHED_NAME = 'schedulerFactoryBean' AND INSTANCE_NAME = 'DESKTOP-7U74VP91539681653705'Copy the code

The following four statements are used to remove unnecessary logs

1. Update the heartbeat time of the current instance to LAST_CHECKIN_TIME

UPDATE JOB_QRTZ_SCHEDULER_STATE SET ….

2. If 0 is displayed, the update fails, add another server instance

INSERT INTO JOB_QRTZ_SCHEDULER_STATE ….

3. Delete outgoing or outgoing records associated with a failed heartbeat instance (FIRED_TRIGGERS)

DELETE FROM JOB_QRTZ_FIRED_TRIGGERS WHERE…

4. Delete the instance where the heartbeat fails

DELETE FROM JOB_QRTZ_SCHEDULER_STATE WHERE… Analyze the source code

This example uses Spring + Quartz +mysql to start;

Quartz. The cluster is configured on the properties attribute org. Quartz. JobStore. IsClustered: true. 1. Let’s start with the definition and initialization of the Spring factory class SchedulerFactoryBean

public class SchedulerFactoryBean extends SchedulerAccessorimplements FactoryBean,

  BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean, SmartLifecycle
Copy the code

1.1 SchedulerFactoryBean implements the InitializingBean interface

During initialization, afterPropertiesSet calls createScheduler to instantiate the property Scheduler (StdScheduler)

@Override public void afterPropertiesSet()throws Exception { if (this.dataSource ==null &&this.nonTransactionalDataSource ! =null) { this.dataSource =this.nonTransactionalDataSource; }... Omit part of the code here... // Get Scheduler instance from SchedulerFactory. try { this.scheduler = createScheduler(schedulerFactory, this.schedulerName); . Omit part of the code here... registerListeners(); registerJobsAndTriggers(); }Copy the code

1.2 SchedulerFactoryBean implements the SmartLifecycle interface

The autoStartup property defaults to true and the start method can be called, which in turn calls the startScheduler method

The startScheduler method finally calls scheduler.start() using the scheduler attribute initialized in step 1.1.

Start () directly calls sched.start() on the StdScheduler instance, which is an instance of QuartzScheduler

GetJobStore ().scheduleStarted() is called by QuartzScheduler’s start method. 2. JobStoreSupport is a basic abstract class for jobStore persistence. GetJobStore ().scheduleStarted() is used. The Initialize () method initializes a ClusterManager daemon thread and calls the Manage method, And start the ClusterManager thread itself. The Manage method calls the doCheckin method for the heartbeat and failover of the nodes in the cluster. ClusterCheckIn (clusterCheckIn, clusterCheckIn, clusterCheckIn, clusterCheckIn, clusterCheckIn, clusterCheckIn, clusterCheckIn) The instanceId of the instance has been regenerated (the default value is a timestamp ending string), so 0 entries must be returned. When 0 entries are updated, the instance does not exist.

The return value of this method is the failed node without heartbeat for a long time. The background premise of this example is that the server is started after the service node is stopped for a period of time, so the heartbeat node recorded in the database has not been updated for a long time. See findFailedInstances ()

After the clusterCheckIn method is executed, the doCheckin method is returned. At this time, there must be failedInstances, namely failedInstances, so the program will run to clusterRecover(conn, failedRecords) method summary

1. Quartz in spring is initialized by SchedulerFactoryBean. SchedulerFactoryBean initializes various resources and schedules by implementing the interface InitializingBean, SchedulerFactoryBean implements Quartz initialization by implementing the interface SmartLifecycle to automatically execute the start method and so on

GetJobStore ().scheduleStarted() is called by QuartzScheduler’s start method. When JobStoreSupport implements this method, it starts a thread, ClusterManager, to detect failed instances at initialization, and also starts the thread to constantly detect failed instances.

3. When a node is recovered or restarted, four SQL statements are executed. The first two SQL statements are used to update or add the heartbeat information of the node. The third is to delete the data FIRED_TRIGGERS of the task triggered by the failed node in the cluster (saving information about which cluster node the task was scheduled by). The fourth SQL statement is to delete the failed node in the cluster.

4. The Failover of quartz cluster is implemented by executing the clusterRecover method repeatedly in the ClusterManager

4.1 When the clusterRecover method is executed, unscheduled tasks are checked on the failed node. When the requestsRecovery attribute of the task is true, the task is directly taken over and run by the current running node.

4.2 When the clusterRecover method is executed, the tasks that have been obtained on the failed node are checked and the status of these tasks is changed from STATE_ACQUIRED to STATE_WAITING so that the properly running nodes in the cluster can obtain the task for scheduling next time