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版本. ...
 
随机推荐
- SMU Spring 2023 Contest Round 1(MINEYE杯第十六届华中科技大学程序设计邀请赛)
			
B. Contest Preparation 对n<=m和n==0时特判一下 #include <iostream> #include <cstdio> #include ...
 - SMU Summer 2023 Contest Round 9(2019 山东省大学生程序设计竞赛)
			
2019 山东省大学生程序设计竞赛 A. Calandar 纯模拟吧(感觉我做麻烦了(?), 就是如果问的是未来的日期,就用相隔天数取模后加上这天的星期, 如果问的是曾经的,就用这天的星期减去相隔天数 ...
 - 2. 从0开始学ARM-CPU原理,基于ARM的SOC讲解
			
关于ARM的一些基本概念,大家可以参考我之前的文章: <到底什么是Cortex.ARMv8.arm架构.ARM指令集.soc?一文帮你梳理基础概念[科普]> 关于ARM指令用到的IDE开发 ...
 - 为什么说 Swoole 是 PHP 程序员技术水平的分水岭?
			
大家好,我是码农先森. 谈到这个话题有些朋友心中不免会有疑惑,为什么是 Swoole 而不是其他呢?因为 Swoole 是基于 C/C++ 语言开发的高性能异步通信扩展,覆盖的特性足够的多,有利于 P ...
 - 【Mac + Appium + Java1.8(二)】之Android模拟器自动化测试脚本开发以及简易例子
			
直接上代码: import io.appium.java_client.AppiumDriver; import org.junit.After; import org.junit.Before; i ...
 - C++ lambda 引用捕获临时对象引发 core 的案例
			
今天复习前几年在项目过程中积累的各类技术案例,有一个小的 coredump 案例,当时小组里几位较资深的同事都没看出来,后面是我周末查了两三个小时解决掉的,今天再做一次系统的总结,给出一个复现的案例代 ...
 - 13 Python面向对象编程:装饰器
			
本篇是 Python 系列教程第 13 篇,更多内容敬请访问我的 Python 合集 Python 装饰器是一种强大的工具,用于修改或增强函数或方法的行为,而无需更改其源代码.装饰器本质上是一个接收函 ...
 - mysql 死锁原因及解决办法
			
Mysql 锁类型 一.锁类型介绍: MySQL 有三种锁的级别:页级.表级.行级. 表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最高,并发度最低. 行级锁:开销大,加锁慢:会出 ...
 - Servlet——简介
			
Servlet 快速入门 1.创建web项目,导入Servlet依赖坐标 <dependencies> <dependency> <groupId>jav ...
 - 【赵渝强老师】MongoDB中的索引(上)
			
索引是提高查询查询效率最有效的手段.索引是一种特殊的数据结构,索引以易于遍历的形式存储了数据的部分内容(如:一个特定的字段或一组字段值),索引会按一定规则对存储值进行排序,而且索引的存储位置在内存中, ...
 
			
		


