Quartz部署了多个节点,为啥总是在特定节点执行

  1. Quartz集群

使用数据库来进行集群的管理

QRTZ_SCHEDULER_STATE 表用来存储各个实例,如下:前两个是运行在同一台Linux上的两个jar包。第三个是运行在一台windows上的jar包。

其中last_checkin_time是每个实例,自己报告的最后时间。

实例在更新自己的last_checkin_time时还会监测其他节点的,如果其他节点在last_checkin_time+last_checkin_tim<System.currentTimeMillis() 当前时间,说明这个节点已经超时未汇报自己的健康状态,此节点可能已经挂掉了

故障恢复:

如果故障节点有执行的任务,那么需要恢复故障任务。如果没有,那么就简单了。直接删除QRTZ_SCHEDULER_STATE的实例即可

注意:各个节点的时间应该同步,否则会出现错误判断的情况。

Quartz采用随机算法。Quartz官网上提到当前,还不存在一个方法来指派(钉住) 一个 Job 到集群中特定的节点。

  1. 任务的执行

QRTZ_TRIGGERS和QRTZ_FIRED_TRIGGERS是两张存储Trigger调度的表

多个实例是靠next_file_time 和 trigger_state来抢夺执行实例。如果多个实例的服务器时间是同步的,那么理论上在两个实例上执行的概率是随机的。实际情况是50.240上Centos系统的时间慢2分钟。这样,也似乎解释了。为啥一旦开启了别的实例。从来没有在Centos上执行过。

如下:

实例A,在QRTZ_TRIGGER表里面查询:条件是,到了next_fire_time并且trigger_state是WAITING的,一旦获取到,就把状态改成ACQUIRED。这样相当于该实例抢占成功。其他实例就无法获取到这条数据了。并且插入qrtz_fire_trigger一条数据,起始状态为ACQUIRED,qrtz_fire_trigger记录。这个表可以理解为正在执行的任务。会记录instance_name。可以知道具体哪个实例在运行

任务执行完成后,在一个事务中触发器状态更新为WAITING,删除FIRED_TRIGGERS表里对应的记录。

  1. 表汇总

QRTZ_BLOB_TRIGGERS 自定义的triggers使用blog类型进行存储

QRTZ_CALENDARS 以 Blob 类型存储 Quartz 的 Calendar 信息

qrtz_corn_triggers:记录cornTrigger的信息。

qrtz_fired_triggers:记录每个正在执行的触发器。

qrtz_job_details:记录每个任务的详细信息。

qrtz_locks:记录程序的悲观锁(防止多个节点同时执行同一个定时任务)。

QRTZ_PAUSED_TRIGGER_GRPS 存储已暂停的 Trigger 组的信息

qrtz_scheduler_state:记录 调度器(每个机器节点)的生命状态。

QRTZ_SIMPLE_TRIGGERS 存储简单的trigger,包括重复次数,间隔,以及触发次数

QRTZ_SIMPROP_TRIGGERS 存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器

qrtz_triggers:记录每个触发器的详细信息。

qrtz_locks存储程序的悲观锁的信息(假如使用了悲观锁)

Quartz提供的锁表,为多个节点调度提供分布式锁,实现分布式调度,默认有2个锁:

STATE_ACCESS主要用在scheduler定期检查是否有效的时候,保证只有一个节点去处理已经失效的scheduler。

TRIGGER_ACCESS主要用在TRIGGER被调度的时候,保证只有一个节点去执行调度。

定时任务就是向triggers和job表里面按规则写入数据。

Logo

更多推荐