Quartz集群原理

传统的Quartz集群是基于数据库实现的,所有的quartz应用节点彼此并没有通信机制。09年terracotta收购Quartz后,才有基于terracotta的分布式的Quartz集群。由于工作中大部分用到的还是基于数据库的集群,这里仅分析基于数据库实现的Quartz集群。

配置集群

Quartz集群配置很简单,只需要quartz.properties中简单的几行配置即可,如下所示:

#开启集群
org.quartz.jobStore.isClustered: true
#保证scheduler的名字相同
org.quartz.scheduler.instanceName: quartzSchedulerCluster

我们要保证scheduler的名字相同,这样Quartz才会认为应用是隶属于同一个集群。

成员签到

刚开始我们就讲,Quartz的集群节点之间是没有通信机制的。若要相互知道对方的存在,只有通过数据库来实现。Quartz有一张叫QRTZ_SCHDULER_STATE的表,字段分别是:SCHED_NAME(集群名称),INSTANCE_NAME(节点名称),LAST_CHECKIN_TIME(上次签到时间),CHECKIN_INTERVAL(循环签到时间间隔)。
在这里插入图片描述
某个quartz节点启动后,第一次签到会向QRTZ_SCHEDULER_STATE插入一条数据。此后每隔一定的间隔时间,再次更新LAST_CHECKIN_TIME。这样,quartz应用通过扫描这个表,就知道集群里有多少个节点了。

心跳机制

我们如何知道某个节点可用呢?Quartz通过循环签到来实现了类似心跳的机制。这里有一个计算公式:

lastCheckin + Math.max(checkInterval, (System.currentTimeMillis() - lastCheckin)) + 7500L > nowTime

我们对于正常的节点,左边的时间在不加上7.5s都应该>=现在的时间的,在加上7.5s后该不等式肯定是应该成立的。对于那些某种原因停掉的应用,因为没有及时签到,即使给了7.5秒的缓冲时间,仍然追不平当前时间,我们就认为该节点挂了。

任务恢复

节点挂掉后,对于已经获取、执行的trigger,我们需要进行恢复,否则其它节点无法接管这些任务。首先Quartz会去QRTZ_FIRED_TRIGGERS表里拿到该节点下的所有trigger,然后释放掉阻塞、获取状态的trigger。
让trigger处于WATING状态,可以继续被其它节点处理。

负载均衡

任务需要执行的时候,是分配到哪一个节点呢?在Quartz中,节点对于任务的处理,都是需要上锁的,锁是通过数据库QRTZ_LOCKS表的行级锁来实现的。
在这里插入图片描述
当获取trigger的时候,会首先通过SELECT * FROME QRTZ_LOCKS WHERE SCHED_NAME = ‘quartzScheduler’ AND LOCK_NAME=‘TRIGGER_ACCESS’ FOR UPDATE来锁住这一行。然后别的节点就无法处理任务了,直到该节点任务处理完了,才会释放锁。

关于锁的机制,在节点成员签到的时候也用到了。成员第一次签到的时候,会锁住集群的STATE_ACCESS记录行,然后插入签到记录。

你可能感兴趣的:(quartz,定时任务框架Quartz系列)