任务调度框架(4)Quartz 分布式实现

分布式定时任务概述

传统定时任务的问题

  1. 单点风险。所有调度都在单台服务器上执行,当任务执行出现问题,整个定时任务就全部终止。
  2. 资源问题。随着业务的增加,定时任务也会增多,单台服务器的执行任务压力会越来越大。

重复执行问题

如果使用分布式定时任务,会有重复执行的风险,一下集中发放可以避免重复执行:

  1. 一台服务器。指定定时任务只在一台机器上启动,但是会有单点风险与资源问题。
  2. 配置参数分散运行。可以创建一个配置项,如任务执行的服务器IP地址,在任务执行时判断。这样可以解决资源不问题,但是依然有单点问题。
  3. 通过全局’锁’互斥执行。使用ZK、Redis或者数据库等方式来实现分布式锁,当节点获取到琐时就执行任务,在没有获取到锁时,不执行。解决了多节点重复执行的问题。

分布式定时任务以及原理

  1. 分布式定时任务框架是在分布式环境中防止多节点同时执行相同的任务时数据被重复处理的框架,并且利用集群的多节点分担大批量任务的处理,提高批量任务的处理效率。
  2. 主要实现方式
  • 抢占式。谁先获得资源谁就先能执行。这种模式无法将单个任务的数据交给多个节点协同处理,一般用于数据量小,任务较多的场景下。
  • 协同式。可以将单个任务处理的数据分到多个节点(JVM)处理,提高数据的秉性处理能力。
  1. 分布式实现的特点
  • 高可用性。分布式部署,提高了系统的高可用性,没有单点风险。
  • 可伸缩性。支持弹性伸缩,可以动态的增加,删除节点,也可以通过控制台部署与管理定时任务
  • 负载均衡。通过集群的方式进行管理任务,可以有效的利用资源,达到负载均衡的效果。
  • 失效转移。任务都可以持久化到数据库或者文件,避免宕机核数据都是引起的隐患。同时有完善的任务失败重试机制和详细的任务跟踪及告警策略。
  1. 分布式锁
  • 基于数据库的实现。依赖数据库的唯一索引实现,想获取锁时,向数据库插入一条记录,执行完成删除对应记录。
  • 基于 Redis。基于redis的setnx 命令实现,为防止死锁,可以对这个key设置超时(expire)时间。
  • 基于 Zookeeper。

Quartz 的分布式模式

概述

  1. Quartz 默认的分布式模式是基于数据库的,其有一套完整的数据库表
  • 只有使用持久化的 JobStore 才能完成 Quartz 集群功能
  • 表文件路径:
    • jar包中 org/quartz/impl/jdbcjobstore/tables_XXXX.sql
    • 源码中 /docs/dbTables/tables_XXXX.sql
  • 目前的版本只有 11 张表(v2.2.1),没有存储 listener 相关的表,多了 QRTZ_SIMPROP_TRIGGERS表
  1. 表详解
表名解释
QRTZ_CALENDARS存储Quartz的Calendar信息
QRTZ_CRON_TRIGGERS存储CronTrigger,包括Cron表达式和时区信息
QRTZ_FIRED_TRIGGERS存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息
QRTZ_PAUSED_TRIGGER_GRPS存储已暂停的Trigger组的信息
QRTZ_SCHEDULER_STATE存储少量的有关Scheduler的状态信息,和别的Scheduler实例
QRTZ_LOCKS存储程序的悲观锁的信息。实现集群机制的关键,主要有几个锁:CALENDAR_ACCESSJOB_ACCESS、MISFIRE_ACCESSSTATE_ACCESSTRIGGER_ACCESS
QRTZ_JOB_DETAILS存储每一个已配置的Job的详细信息
QRTZ_SIMPLE_TRIGGERS存储简单的Trigger,包括重复次数、间隔、以及已触的次数
QRTZ_BLOG_TRIGGERSTrigger作为Blob类型存储
QRTZ_TRIGGERS存储已配置的Trigger的信息
QRTZ_SIMPROP_TRIGGERS

配置实现

  1. jobStore的配置
  • RAMJobStore 是基于内存实现的。存取速度快,容易丢失数据。
  • JobStoreSupport 是基于 JDBC 实现的,将 TriggerJob 存储在数据库。
  • dataSource 可以与业务数据公用库,统一配置,并且设置在 SchedulerFactoryBean
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.maxMisfiresToHandleAtATime = 1
org.quartz.jobStore.misfireThreshold = 120000
org.quartz.jobStore.txIsolationLevelSerializable = false # 修改为true, mysql有可能会有死锁

#==============================================================
#Configure DataSource (建议在配置 SchedulerFactoryBean 的时候,注入配置的 factory.setDataSource(dataSource); 省略这边的配置)
#==============================================================
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = 你的数据链接
org.quartz.dataSource.myDS.user = 用户名
org.quartz.dataSource.myDS.password = 密码
org.quartz.dataSource.myDS.maxConnections = 30
org.quartz.jobStore.selectWithLockSQL = SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE
  1. JobStoreSupport 概述
  • 主要实现有 JobStoreTXJobStoreCMT
  • 事务问题。如果您不需要将调度命令(例如添加和删除 triggers)绑定到其他事务,那么可以通过使用 JobStoreTX 作为 JobStore 来管理事务。JobStoreCMT 依赖于正在使用Quartz的应用程序管理的事务。
  • DriverDelegate 代表了解不同数据库系统的特定方言,负责执行特定数据库可能需要的任何JDBC工作。StdJDBCDelegate 用于完全符合JDBC的驱动程序,一般没有特定的就使用这个
  1. 其他属性
  • tablePrefix JDBCJobStore 的表前缀属性。是在数据库中创建的Quartz表的前缀的字符串。
  • isClustered 设置为true以打开群集功能。如果有多个Quartz实例使用同一组数据库表,则此属性必须设置为true
  • clusterCheckinInterval 设置此实例checkin与群集的其他实例的频率,以毫秒为单
  • dataSource 此属性的值必须是配置属性文件中定义的 DataSource 的名称。
  • maxMisfiresToHandleAtATime 在给定的通行证中,工作区将处理的最大错误次数触发。一次处理很多可能导致数据库表被锁定得足够长,以致可能会阻碍其他(未失败的)Triggers 触发的性能
  • misfireThreshold 在被认为misfire之前,调度程序将容忍一个Triggers将其下一个启动时间通过的毫秒数。默认 60000(60秒),单位毫秒。
  • txIsolationLevelSerializable 设置数据库隔离级别为 Serializabletrue 表示在 JDBC 连接上调用 setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)。这可以有助于防止在高负载下的某些数据库的锁定超时以及持久事务。在 mysql中设置为true,可能会有死锁的风险。

参考

  1. 源码地址 Learning_Job_Schedule
  2. quartz (从原理到应用)详解篇
  3. Quartz配置JDBC-JobStoreTX
  4. Quartz配置JDBC-JobStoreCMT
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值