【故障排查】10分钟解决Quartz重复调度的疑难杂症
内容提要
本文介绍了使用Apache DolphinScheduler作为调度结构时,解决Quartz重复调度问题的过程。通过排查日志和分析数据库的锁记录,发现问题是由于Tidb数据库在RR隔离级别下,读取的是之前的Read View导致的。解决方案是切换到Mysql数据库或将Tidb数据库更改为RC隔离级别。
延伸解读
问题根源:TiDB与MySQL的Read View创建时机差异
文章指出,在RR隔离级别下,MySQL在事务中第一次快照读时才创建Read View,而TiDB在开启事务时即创建Read View。这导致TiDB中后续的快照读可能读取到事务开始前的旧数据。在Quartz调度中,第二个线程获取锁后查询QRTZ_TRIGGERS表时,可能读到与第一个线程相同的旧数据,从而重复触发同一任务。
排查关键:全量SQL日志与锁等待分析
作者通过开启TiDB全量日志,发现第二次调度在SELECT QRTZ_TRIGGERS时返回了与第一次相同的记录,尽管第一次调度已更新了NEXT_FIRE_TIME。进一步检查锁记录,发现第二个进程等待锁约7秒,但获取锁后仍读取到旧数据。这排除了主从同步问题,将焦点转向数据库隔离级别行为差异。
解决方案:切换MySQL或调整TiDB隔离级别
基于复现实验,文章建议将底层数据库从TiDB切换为MySQL,或将TiDB的隔离级别从RR改为RC。在RC级别下,每次快照读都会创建新的Read View,从而避免读取到过期数据。这一调整能有效解决因Read View时机差异导致的Quartz重复调度问题。
Q&A
Quartz重复调度问题的原因是什么?
Quartz重复调度问题源于Tidb数据库在RR隔离级别下读取的是之前的Read View。
如何确认Quartz重复调度是由什么引起的?
通过排查日志和分析数据库的锁记录,确认是Quartz引起的重复调度。
解决Quartz重复调度问题的建议是什么?
建议切换到Mysql数据库或将Tidb数据库更改为RC隔离级别。
在使用Apache DolphinScheduler时,Quartz的底层调度结构是什么?
Quartz的底层调度结构是QRTZ_TRIGGERS和QRTZ_FIRED_TRIGGERS表。
为什么Tidb和Mysql在RR隔离级别下的行为不同?
Tidb在开启事务时会立即创建Read View,而Mysql在同一事务中的第一个快照读才会创建Read View。
如何通过日志排查Quartz重复调度的问题?
可以通过开启MVCC日志和全量日志,分析QRTZ_TRIGGERS和QRTZ_FIRED_TRIGGERS表的记录来排查问题。