# 一、定义

Quartz是一个分布式定时任务框架,底层采用Java编写,利用数据库存储任务及调度信息,并利用数据库的主键/唯一键实现分布式锁,解决分布式环境下同个任务被多创建和多执行的问题(锁机制 + 任务状态)。Quartz具有以下特点:

  1. 高灵活性:Quartz提供了丰富的调度配置选项,可以按照需要定制任务调度策略,支持定时、周期性和cron表达式等多种任务调度方式。
  2. 高性能:
  3. 高可靠:
    • 持久化机制:任务和触发器信息都存储在数据库中,保证了任务的可靠性,即使程序崩溃也可以从数据库获取任务信息重新执行。
    • 集群支持:即使有部分节点失败了,仍然可以由其他节点接管任务并执行。
    • 错误处理机制:Quartz提供了监听器功能,能够监听任务、触发器的生命周期,捕获期间可能的异常,并根据其状态执行对应的预置函数,提供任务补偿机制。
  4. 原子性:通过LOCKS表存储任务锁(触发器名、锁名、任务名),当有其他节点调用该触发器的时候,会去检查LOCKS表中是否已经存在锁,存在则说明任务被其他节点执行。

核心组件:

  • 触发器:记录调度策略,绑定任务,一个触发器对应一个任务

  • 任务:记录具体的要执行的任务信息(如哪个类的方法),与触发器是一对多关系,一个任务可以有多个触发器。

  • 监听器:监听触发器、任务的生命周期,提供钩子预置处理方法,根据状态执行对应的预置方法。

  • 锁:存储【触发器-任务】锁,在触发任务的之前,先尝试加锁,成功则插入锁记录并执行,否则说明该任务被其他节点执行中。

# 二、生命周期

  1. 初始化数据库表:触发器、任务、监听器、锁
  2. 创建触发器、任务、监听器等,绑定后会持久化到数据库中,此时的触发器状态为【等待触发】
  3. 调度器会定期从触发器表中获取触发信息,并根据以下属性【触发时间-优先级-创建时间】进行排序,并存储在优先队列中。每次调度器会从头检查触发器,直到找到可以触发的任务(多节点下会重复获取触发器,但是Quartz有分布式锁机制避免重复执行,所以头部的触发器可能被其他节点执行中),找到触发器后则尝试插入分布式锁,成功则执行,执行完后由于其他节点中仍然保存着已经被执行的触发器信息,需要保证节点间的队列数据一致,Quartz采用JGroups库实现分布式通信。
    • JGroups分布式通信:每个节点都会向其他节点广播自己的触发器删除信息,其他节点收到消息后会删除相应的触发器,保证内存队列的一致性。
      • Quartz通过Misfire机制保证不同节点的队列在不一致时也不会重复执行。如果因为网络问题导致某个节点没有接收到触发器删除的广播信息,则出现不同节点队列不一致问题,也就是说同个触发器可能被执行两次,Quartz的Misfire机制是通过计算【预期执行时间-当前时间】,如果触发该任务的时候其他节点在执行导致执行失败,则将其标记为misfired的触发器,后续调度的时候会优先获取非misfired的触发器进行执行。
    • 优先队列:优先队列的底层采用的是堆的数据结构,通过对触发器构建堆后
      • 删除:需要遍历整个堆并找到对应触发器删除,时间复杂度为O(n)(也可以通过建立哈希表快速定位触发器),在堆中,删除元素是将最后一个元素覆盖要删除的元素,并重新调整堆。
      • 增加:新加入节点,并调整堆结构。
      • 更新:遍历或者通过哈希表快速定位触发器并更新。
Last Updated: 2023-2-21 1:29:35 ├F10: AM┤