spring quartz 部分定时任务不执行问题定位修复方案

Quartz部分定时任务不执行问题分析过程及修复方案

背景:
2021年1月7号上线迁移需求之后,出现最为明显的 文件上传 其他部分定时任务也不执行的情况 执行时间并没有按照约定时间去执行

分析1 怀疑是代码问题?

 对文件上传定时任务代码进行排查 并无发现编码问题,并且对1月7号上的版本 和上一个版本进行代码比对 并未发现对众邦的代码有所改动的地方

分析2 项目定时任务框架 spring quartz 内部任务存储 调度问题?

  Quartz 是基于RAMJobStore调度中心去调度的,里面有Job(任务),Trigger(触发器)。

  通过对项目定时任务代码的了解 及源码的分析 得知:

项目启动时 会把quartz.xml配置文件中的所有定时任务加载到jobDefinitions 这个队列中,遍历jobDefinitions 把每个定时任务的 job 和 Trigger获取到,通过Quartz API 把定时任务添加到RAMJobStore, 经过对jobDetail的校验 ,这里主要是校验name,group,jobClass 是否为空,然后jobDetail的下次触发时间是否合法 然后添加到RAMJobStore(JobWrapper, TriggerWrapper)中。
秉着这一逻辑思想
1月14号上线 项目重启后 拉取项目 堆栈包heap1.hprof
使用jprofiler分析工具 打开heap1.hprof
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如图 找到RAMJobStore中的两个存储对象 发现job 和 trigger中存储的数量是一致的,于是我打算点对点的排查 由于生产最为明显的是众帮文件上传定时任务不执行 所以我从这76任务中,找到众帮文件上传的wrapper 看看是不是有什么问题。在这里插入图片描述
如图可以看出 文件上传的定时任务 从开始执行时间,下次触发时间,是否有配套的监听器 都是正常的 ,可就是不执行,于是我开始quartz调度的过程,如何调度的执行的。
几经翻查 发现quertz 定时任务在调度时,都需要初始化一个线程池SimpleThreadPool 而这个线程池大小默认是10,而quertz任务触发调度的原则是:
1、线程池资源获取等待定时任务过期作废机制。
2、Quartz框架的定时任务执行是绝对时间触发的,所以存在“过期不候”的现象。

所以开始怀疑是项目定时任务过多87个 并且大部分定时任务都是 10秒 ,20秒,30秒 1分钟执行一次 过于密集

分析3 quartz 调度初始化没有问题 定时任务多,且时间密集导致?

为了复现和生产一样的情况 众帮及其他部分定时任务不执行的情况,由于测试环境基本没有数据,所以每个定时任务执行的非常快,所以不存在生产的情况,所以我把代码中每个定时任务 让他们执行时,都线程等待60秒,并且做了一个定时任务计数器。
“fpc######ck”:205,
“ali######ule”:1657,
“bdT######ack”:680,
“net######ule”:5,
“pro######ule”:976,
“pap######ule”:203,
“fp######ck”:124,
“jd######ule”:828,
“pa######ule”:312,
“ca######k”:511,
“fp######ple”:1260,
“fp######le”:1282,
“ws######ate”:9,
“zhon######ew”:“1”,
“sen######b”:“1”,
“AliP######lysis”:393,
“ppl######ule”:33,
“se######igrate”:18,
“b######List”:46,
“se######an”:15,
“cre######ck”:1312,
“fil######ule”:1529,
“p######ndRule”:127,
“jL######ack”:62,
“q######Rule”:2,
“Op######etCheck”:54,
“zb######ck”:3,
“yj######oan”:5,
“gjj######ack”:101,
“ppd######ule”:82,
“ali######ule”:1687,
“jfDa######ule”:506,
“jf######ack”:17,
“ql######ack”:2,
“bd######ule”:4966,
“alip######ule”:1673,
“file######ack”:3123,
“you######ule”:6,
“pp######ck”:4,
“bd######ack”:794,
“ws######ule”:12,
“b######igrate”:3045,
“se######pJob”:1102,
“Od######itor”:1321,
“est######onitor”:25,
“qia######Back”:4,
“yx######ack”:“1”,
“jL######Rule”:605,
“zb######dRule”:2,
“cx######le”:535,
“bd######le”:3224,
“bd######ck”:1020,
“fil######ad”:678,
“bd######te”:2043,
“yx######ndRule”:6,
“sen######Loan”:11,
“pp######Back”:9,
“ws######ule”:10,
“df######k”:477,
“cxl######le”:475,
“gjj######ule”:725,
“qi######dRule”:519,
“qlC######ack”:“1”,
“file######BD”:386,
“ts######ck”:“1”,
“ts######dRule”:“1”,
“yx######ule”:6,
“bdA######dRule”:6760,
“yjD######ule”:8,
“jd######ck”:1153,
“bd######rate”:1913,
“ws######tDate”:9,
“yj######AndRule”:8,
“fpl######dRule”:1308

从计数器打印结果可以看出
在测试环境执行了15小时左右 果然出现了和生产一样的情况
一共87个定时任务 执行了73个有19个未执行 已执行的存在执行次数为个位数的情况

所以我认定quartz定时任务执行存在线程瓶颈 与此我发现为什么众帮的文件上传一次执行的机会都不能抢到吗?想必小伙伴们也会有这种猜疑 就算触发时间相同情况下 可触发的数量有限 难道zho******wJob 一次都抢不到执行线程吗?

于是 又一顿的百度 博客 终于找到了对应的解释
默认情况是触发时间先后顺序排列,触发时间比较前的先执行任务,但如果一个或多个任务同时在相同时间触发下,触发器设置优先级越高越先执行。如果优先级相同,则跟任务的存储方式有关,RAMJobStore时与TriggerKey排序有关,即按触发器名的字母序;如果是JdbcStore则跟数据库查询的默认排序有关了。Trigger优先级默认为5,数值越大优先级越高

这会大家应该明白了吧 众邦的定时任务名称叫做 zho******wJob 所以 在相同触发条件下 并且执行数量有限的情况下,他被淘汰了

**

问题解决:

那么此时留下的问题就是 解决 quartz执行线程数量太少10个的问题
我们要做的就是 增加quartz 执行线程数量
由于本项目 quartz 的框架版本过低1.5.2 无法通过quartz.properties
进行声明线程数量 这里我就不想吐槽了 试了很多种办法不行 ,而且版本调整到2.0.0以上后 系统封装的quarzt代码全部报错 版本完全不兼容。
于是我们在quartz.xml中
在这里插入图片描述

在SchedulerFactoryBean中对quartz.properties进行复写 并且改变线程数量为100,以及Trigger检查器 默认每次只Acquire一个Trigger。

丢到测试环境测试 定时任务计数器打印结果如下:
“b######Rule”:128,
“fp######eople”:14,
“g######ck”:14,
“you######Rule”:16,
“jd######ack”:15,
“jfC######ack”:31,
“bdA######itMigrate”:30,
“sen######DLoan”:32,
“pplD######le”:15,
“est######onitor”:“1”,
“fp######le”:11,
“ws######itDate”:9,
“cr######lBack”:7,
“pa######ndRule”:10,
“tsz######ndRule”:12,
“ppd######Rule”:51,
“wsd######itAckDate”:19,
“df######k”:10,
“yx######dRule”:43,
“zhon######Up2View”:2,
“qian######dRule”:11,
“fpc######Rule”:12,
“cal######ck”:9,
“pap######dRule”:11,
“p######ck”:11,
“bl######t”:2,
“yjS######xnLoan”:39,
“ppc######dRule”:20,
“cxl######dRule”:10,
“y######llBack”:14,
“gj######dRule”:23,
“proc######Rule”:19,
“sen######oan”:37,
“pp######ack”:15,
“alip######dRule”:8,
“qlLo######ack”:8,
“ql######ack”:6,
“bd######nDataAndRule”:129,
“qlD######ule”:8,
“file######lBack”:156,
“pla######onitor”:2,
“yjFil######taAndRule”:49,
“fpl######ack”:10,
“bdA######CallBack”:19,
“bdAdjustm######aAndRule”:149,
“sendT######tMigrate”:39,
“bd######Back”:14,“fpcCallBack”:9,
“bd######grate”:35,
“yj######ule”:39,
“cx######dRule”:14,
“bdT######CallBack”:24,
“send######pJob”:22,
“fileD######UpBD”:24,
“ali######ule”:8,
“Open######Check”:3,
“file######oad”:7,
“A######xtAnalysis”:11,
“qlL######aAndRule”:14,
“jfDa######Rule”:10,
“qi######allBack”:24,
“bd######grate”:35,
“alip######ndRule”:13,
“wsdD######Rule”:38,
“jdD######ule”:15,
“yxD######Rule”:8,
“sen######b”:19,
“ws######dRule”:37,
“yx######ck”:10,
“Od######tor”:14,
“file######ule”:36,
“zb######ck”:15,
“tsz######ack”:11,
jLF######Rule":13,
“jL######ack”:9,
“zbD######Rule”:39

从结果中可以看出 每次定时任务都执行了,并且执行的次数都比较均匀,不像一开始 有的执行几千次,有的执行几十次,受线程执行数 已经定时任务首字木影响较大。 而且从结果中可以看出 众帮的数据处理执行了39次 众邦的文件上传 每10分钟执行一次 每次轮到执行的执行时,都执行了,不存在拿不到执行线程的情况

quartz定时任务使用结论

1、线程池资源获取等待定时任务过期作废机制。
2、Quartz框架的定时任务执行是绝对时间触发的,所以存在“过期不候”的现象。
3、在使用Quartzs框架时,一定要预先计算好triggers数量与线程池大小的匹配程度,资源一定要够,或者任务执行密度不能太大,否则等到线程任务释放完,trigger早已过期,就无法按预期时间触发了。
4、在进行业务代码开发过程中 尽量一个定时任务中处理多种业务代码,做异步线程处理,对定时任务进行归类 抽取
5.根据业务情况 不要一上来就增加定时任务,靠定时任务处理问题

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GQ·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值