这个问题困扰了我很久, 从开发的时候就发现这个组件在我们项目中是个风险点。
虽然我本身不是负责该模块开发的,但是基于一颗好奇心,我找了一份网上基础课程,了解了这个组件的基本原理。
不得不庆幸这个决定,因为上线当天,以及上线后运维期的重大问题,都和这个组件有关,而这些问题都被我暂时处理了。
这个是我的学习笔记:http://note.youdao.com/noteshare?id=ec97c4f425aaaa8513d297e358163255
开发环境遇到的问题:
1、 开发者 A 、B、 C 同时启动已经集成了定时任务的应用,连接同一个数据库时,会在 qz_scheduler_state 上为
每个机器生成一个调度,但实际情况是: 你会发现不一会,qz_locks 这个表会产生死锁。
qz_lock 表,有两条数据:STATE_ACCESS TRIGGER_ACCESS
在执行定时任务时,quartz模块会将这一条数据 for update ,生成行锁,这样就能保证定时任务能被唯一执行。
死锁的发生,具体原因,我搜索了一下:
https://blog.csdn.net/qq_16681169/article/details/74784193
大概有两种: 一、 A、 B 交叉访问, 我觉得 quartz 死锁应该不属于这种情况。
二、A、B 共享锁 (for update) , 当 A 需要修改时,共享锁上升为 排它锁, 同时 B 也需要同时修改,
B 也需要将 它的共享锁上升为排它锁,由于 共享锁 到 排它锁 存在转换时间,且两种所不兼容,
导致锁等待, 实际中 也可以发现: lock wait 的提示;
2、 单机定时任务,没有任何问题。
实际生产中遇到的问题:
1、 上线当天,发生了由于 qz_lock 缺少数据(本身应该有两条,实际只有一条),导致自动任务无法自动开启。
补充数据后,自动任务可以正常运行。
2、 运行期间,发生主从库,schedule 调度表数据库不一致,而同步失败的情况。
发生这个问题的原因,个人推测有两个原因:
(1) 我做容灾测试时,模拟主从库宕机,当时部分应用正在跑自动任务,导致主从库注册的调度机器不一致。
(2)上线前数据清理少了这个组件的表;
我觉得:
定时任务应该不与应用耦合,迁移出去,其他应用有定时任务的开放接口。
定时任务单点部署,主要是因为定时任务没有很大负载。
数据库,由于quartz 基于数据库行锁,可以建立单库,供 quartz 进行任务数据的固化。