quartz集群增强版🎉
quartz集群增强版
这是除了mee_admin之外,投入时间精力最多的一次开源了,quartz集群增强版
前前后后花费了我四月有余的时间精力开发而来,实属不易~
先简要的说下:quartz集群增强版
由quartz
的 2.3.2
版本改造,对原有功能进行了部分缩减, 同时也对现有的痛点做了大量的增强,这些增强包括但不限于如下:
1. 修改任务参数序列化及存储
将默认参数存储方式由blob
大字段方式修改为定长字符串方式,保证后管修改即所得,同时内部使用 org.json
库对json字符串序列化及反序列化,使用起来更便捷
同时也将传参配置由原版的 K/V
(对象序列化) 改为(Map
)对象(eg:{"aa":1}
)或(Array
)列表(eg:[11,true,{"bb":"her"}]
) 的方式,使用时视json结构,可使用
context.getJobDataMap()
或 context.getJobDataList()
直接获取配置的json参数,更简单快捷;顺带一提:也可通过 context.getJobData()
拿出原始存储的json字符串
2. 分离了执行端及配置管理端
这是很大的改变,如果是执行端使用,只需添加依赖 quartz-core
,如果是后管配置则只需要连接执行库(数据库)后使用依赖 quartz-client
来配置,管理集群或分布式的执行端也只需要
使用此来配置即可(前提是连接同一个库表), 这个改变在原版的quartz中是不可想象的,原版的quartz
执行端与配置端耦合这种不太美妙的方式着实令人头疼与不解
3. 使用乐观锁
这同样也是重大的变化,原版采用lock
表行级悲观锁,每次变更都要竞争同一个 STATE_ACCESS
或 TRIGGER_ACCESS
,同时每次执行加锁释放锁的过程还需配合线程本地变量(ThreadLocal
)来使用,看起来有些没必要而十分的笨重的同时系统开销也比较大
quartz集权增强版
不再使用 lock
表悲观锁,而是使用 UPDATE ... WHERE ...
方式(乐观锁),虽同样存在一定的查询开销,但写db的开销大大地减少了。
同时,需要说明的是使用乐观锁似乎还是有些不够,可目前并没有测试出bug(也许是测试不够严格吧...),如果有好的idea 恳请告知哈~
4. 简化了表结构以及数量
由于底层去掉了trigger
及 memory
单机等相关逻辑,故表结构及逻辑也做了相应的简化,由原版的11张表简化为4张表,对,没错~,就是四张表,四张表就ok
表的整体设计主要参考了 mee_timed 这个同样由我写的定时任务组件,目前 这四张表为:
- QRTZ_APP 应用表: 用于定义应用,尤其是对于管理分布式应用十分有用,同时执行端启动时会自动新增或更新 无需手动添加数据
- QRTZ_NODE 节点表:用于定义应用下的执行节点,这是对于集群应用十分有用,比如你需要增量发布时可通过启停节点以增量更新执行端,同样表数据也是自动新增或更新,十分方便
- QRTZ_JOB 任务配置表: 配置任务的基本信息(不包含执行事件项,一个job任务对应多个执行配置/时间项),此表主要定义任务的执行类以及关联的应用信息
- QRTZ_EXECUTE 执行配置表: 执行配置必须关联一个任务配置(job),执行配置也有独立的状态可供后管操作
5. 去掉了group
(组)
这是个不太有用
的概念,组在绝大数使用quartz
的开发者来说十分困惑(至少我经历的项目大多是这样),group
的使用如有不慎会跟预期存在差异,因为有 group
这一层的存在,配置任务也略显有些臃肿。。。
去掉了 group
的同时也去掉了 TriggerKey
及相关的逻辑,这样就基本淡化了 group
的概念及使用,好处不言而喻。
6. 兼容原版quartz的配置项及集成方式
对于常用的springboot
框架,集成方式与原版的quartz
的方式并无太大区别,主要区别是只需导入 quartz集群增强版
提供的表即可,starter
(autoconfigure
)中无用的配置类及方法都做了兼容
还有就是原有的context
稍有变化,主要是去掉了TriggerKey
以及增强json
传值带来的变更,基本使用就无任何区别~
7. 缺火/熄火(MisfireHandler)及集群(ClusterManager)处理
首先,这个变更也蛮大的。。。
先说下缺火是什么,由于quartz
内所有执行时间点都是通过对应类型的 Trigger
(eg: CronTriggerImpl
、 SimpleTriggerImpl
) 计算出来的,一旦出现不可预知的错误以及停机,则执行时间点无法向前推进,如果补偿或恢复机制,则 fireTrigger
的任务扫描无法扫到造成任务无法继续执行,这就是缺火(Misfire
),
解释的并不好,请大神给斧正哈
因为原版的quartz在这两块存在并发(集群) 以及全局悲观锁的存在,一旦触发 Misfire
则可能导致任务存在不可知的问题,同时 MisfireHandler
、ClusterManager
为两个独立不同的线程任务(轮询),但使用的锁是同一把,逻辑处理就存在时效性问题(延迟)
所以对于本 quartz集群增强版
就不同了, 现在我将这两招合一, 使用 ClusterMisfireHandler
来处理 Misfire
任务以及节点check及清理任务,同样是使用数据库锁,但是在 ClusterMisfireHandler
内部做了并发优化,以保证同一时间一个应用下只有一个节点执行,这点而很重要!
8. 其他
- 简化了线程池的管理同时也兼容原有的
SimpleThreadPool
- 由于传参的变化也无需对存储参数的大字段的操作做各个厂商的数据库的兼容
架构设计
quartz-client
+后管集成效果
目前可能存在及已知的问题
- 不管是 ClusterMisfireHandler 维护集群及缺火,还是 QuartzSchedulerThread 扫任务 都是按频度来的,其中 QuartzSchedulerThread 是5s一次循环 ,ClusterMisfireHandler 则是15s一次循环,这样问题就来了
- 添加任务时,若您是10点整添加的任务则任务最快也得10点过5s后才可执行,这是目前 任务扫描的频度及当前架构而为之的
- QuartzSchedulerThread 在扫描批次任务后不断循环以到执行时间点时,若关闭节点及应用也只有等当前次执行完成后才会停止任务
- QuartzSchedulerThread 的锁的处理(集群环境下如何保证一个任务只被一个节点执行)可能存在缺陷,但目前排查不出问题,这需要使用者花时间测试以排查根本原有
- 去掉 group 对于 group 的使用者来说这是不好的消息,这算一个吧
- 目前仅支持 postgresql、mysql、oracle 这三个厂商的数据库支持,并经过测试通过,这是使用限制
- client sdk (
quartz-client
) 虽已经过测试通过,可能存在未知bug及设计缺陷
quartz集群增强版🎉的更多相关文章
- Quartz集群
为什么选择Quartz: 1)资历够老,创立于1998年,比struts1还早,但是一直在更新(27 April 2012: Quartz 2.1.5 Released),文档齐全. 2)完全由Jav ...
- 项目中使用Quartz集群分享--转载
项目中使用Quartz集群分享--转载 在公司分享了Quartz,发布出来,希望大家讨论补充. CRM使用Quartz集群分享 一:CRM对定时任务的依赖与问题 二:什么是quartz,如何使用, ...
- 使用sqlserver搭建高可用双机热备的Quartz集群部署【附源码】
一般拿Timer和Quartz相比较的,简直就是对Quartz的侮辱,两者的功能根本就不在一个层级上,如本篇介绍的Quartz强大的序列化机制,可以序列到 sqlserver,mysql,当然还可以在 ...
- Springboot2.X集成Quartz集群
为什么要使用Quzrtz集群 在项目进行集群部署时,如果业务在执行中存在互斥关系,没有对定时任务进行统一管理,就会引起业务的多次执行,不能满足业务要求.这时就需要对任务进行管理,要保证一笔业务在所有的 ...
- 双机热备的Quartz集群
sqlserver搭建高可用双机热备的Quartz集群部署[附源码] 一般拿Timer和Quartz相比较的,简直就是对Quartz的侮辱,两者的功能根本就不在一个层级上,如本篇介绍的Quartz ...
- quartz集群报错but has failed to stop it. This is very likely to create a memory leak.
quartz集群报错but has failed to stop it. This is very likely to create a memory leak. 在一台配置1核2G内存的阿里云服务器 ...
- Quartz集群配置
先看看quartz的持久化基本介绍: 引用 1 大家都清楚quartz最基本的概念就是job,在job内调用具体service完成具体功能,quartz需要把每个job存储起来,方便调度,quartz ...
- Quartz集群原理及配置应用
1.Quartz任务调度的基本实现原理 Quartz是OpenSymphony开源组织在任务调度领域的一个开源项目,完全基于Java实现.作为一个优秀的开源调度框架,Quartz具有以下特点: (1) ...
- quartz集群调度机制调研及源码分析---转载
quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...
- (4) Spring中定时任务Quartz集群配置学习
原 来配置的Quartz是通过spring配置文件生效的,发现在非集群式的服务器上运行良好,但是将工程部署到水平集群服务器上去后改定时功能不能正常运 行,没有任何错误日志,于是从jar包.JDK版本. ...
随机推荐
- Deformable DETR:商汤提出可变型 DETR,提点又加速 | ICLR 2021 Oral
DETR能够消除物体检测中许多手工设计组件的需求,同时展示良好的性能.但由于注意力模块在处理图像特征图方面的限制,DETR存在收敛速度慢和特征分辨率有限的问题.为了缓解这些问题,论文提出了Deform ...
- sc2 天梯地图
没记错的话以前 7 张 ban 3 张,非常合理,现在 9 张怎么还是 ban 3 张 好哥哥达蒙星际2教学 Goldenaura ban 三四矿近,挂运输机的地方长,架坦克的点位多,ZvT 打不了一 ...
- Java常用类——包装类 小白版个人推荐
包装类及自动装箱/拆箱 包装类是将Java中的八种基本数据类型封装成的类,所有数据类型都能很方便地与对应的包装类相互转换,以解决应用中要求使用数据类型,而不能使用基本数据类型的情况. int a = ...
- 1分钟掌握变速效果,让你的视频快慢自如----蓝松视频编辑SDK
2. 变速调整默认速度是1X就是正常播放速度,可以通过调节滑块,实现视频中的慢镜头动作 3.只需一行代码设置播放速度/** 视频的播放速度; 范围是 0.1---10.0 默认1.0; 正 ...
- TCP/TP协议栈(逐渐更新版)
TCP/IP协议栈 应用层 DNS协议 传输层 TCP协议 TCP协议报文结构 源端口 目的端口 序列号 确认号 头长度header length or data offset 保留字段reserve ...
- SQL中解决i+1 & values中插入变量
基于JDBC环境下使用mysql插入数据的一些小问题 下方代码用于实现 批量向数据库中插入数据 一般为"垃圾"数据 代码例子实现i+1的效果 i=1 i+1=2 for (int ...
- TS中简单实现一下依赖注入
依赖注入(Dependency Injection,DI)是一种设计模式,主要用于实现控制反转(Inversion of Control,IoC).它通过将对象的依赖关系从内部管理转移到外部容器来解耦 ...
- SQL Server Temporary Table & Table Variable (临时表和表变量)
参考: 在数据库中临时表什么时候会被清除呢 Temporary Tables And Table Variables In SQL 基本常识 1. 局部临时表(#开头)只对当前连接有效,当前连接断开时 ...
- C++11 线程同步接口std::condition_variable和std::future的简单使用
std::condition_variable 条件变量std::condition_variable有wait和notify接口用于线程间的同步.如下图所示,Thread 2阻塞在wait接口,Th ...
- SQL通用语法与分类
通用语法 1.SQL可以单行或多行书写,以分号结尾. 2.MySQL数据库的SQL语句不区分大小写,关键字建议使用大写. 3.注释 1)单行注释: -- 注释内容 或 # 注释内容(MySQL特有) ...