quartz详解3:quartz数据库集群-锁机制
来源:互联网 发布:淘宝运动服 编辑:程序博客网 时间:2024/06/06 12:48
http://blog.itpub.net/11627468/viewspace-1764753/
一、quartz数据库锁
其中,QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,其表结构如下:
注:此表结构在2.2版本有新增字段,这里暂时不考虑。
可以看出QRTZ_LOCKS中有5条记录,代表5把锁,分别用于实现多个Quartz Node对Job、Trigger、Calendar访问的同步控制。
关于行锁的机制:
1、mysql > set autocommit=0; //先把mysql设置为不自动提交。
2、 select * from es_locks where lock_name = 'TRIGGER_ACCESS' for update ; //线程一通过for update 可以把这行锁住
3、 select * from es_locks where lock_name = 'TRIGGER_ACCESS' for update ; //线程二通过for update 无法获得锁,线程等待。
4、commit; //线程一通过commit 释放锁
5、 //线程二可以访问到数据,线程不再等待。
所以,通过这个机制,一次只能有一个线程来操作 加锁 - 操作 - 释放锁。 如果 操作 的时间过长的话,会带来集群间的主线程等待。
数据库行锁是一种悲观锁,锁表时其它线程无法查询。
源码中关于数据库集群加锁的方法有如下几种:
1、executeInNonManagedTXLock方法的含义是自己管理事务,不让容器管理事务的加锁方法。三个参数lockName的值是上面所说的TRIGGER_ACCESS,表示要加锁的类型。
txCallback是加锁后再回调的方法。
txValidator是验证方法,一般为null
函数先执行加锁,再回调要操作的方法,然后再解锁。
看一下源码:
2、如果不是通过这种回调方法的加锁,一般是:
getLockHandler().obtainLock
执行
commitConnection(conn)
releaseLock
cleanupConnection
二、源码分析锁
先了解一篇文章,通过源码来分析quartz是如何通过加锁来实现集群环境,触发器状态的一致性。
http://www.360doc.com/content/14/0926/08/15077656_412418636.shtml
可以看到触发器的操作主要用主线程StdScheduleThread来完成,不管是获取需要触发的30S内的触发器,还是触发过程。select和update触发器表时
都会先加锁,后解锁。如果数据库资源竞争比较大的话,锁会影响整个性能。可以考虑将任务信息放在分布式内存,如redis上进行处理。数据库只是定时从redis上load数据下来做统计。
参考:quartz详解2:quartz由浅入深 查看第四章第1,2节
实现都在JobStoreSupport类
加锁类型加锁方法底层数据库操作备注executeInNonManagedTXLockacquireNextTriggerselectTriggerToAcquire
selectTrigger
selectJobDetail
insertFiredTrigger查询需要点火的trigger
选择需要执行的trigger加入到fired_trigger表for执行 triggerFiredselectJobDetail
selectCalendar
updateFiredTrigger
triggerExists updateTrigger点火trigger
修改trigger状态为可执行状态。recoverJobsupdateTriggerStatesFromOtherStates
hasMisfiredTriggersInState doUpdateOfMisfiredTrigger
selectTriggersForRecoveringJobs
selectTriggersInState
deleteFiredTriggers非集群环境下重新执行
failed与misfired的triggerretryExecuteInNonManagedTXLockreleaseAcquiredTriggerupdateTriggerStateFromOtherState
deleteFiredTrigger异常情况下重新释放trigger到初使状态。triggeredJobCompleteselectTriggerStatus
removeTrigger updateTriggerState
deleteFiredTrigger触发JOB任务完成后的处理。obtainLockrecoverMisfiredJobshasMisfiredTriggersInState doUpdateOfMisfiredTrigger重新执行misfired的trigger
可以在启动时执行,也可以由misfired线程定期执行。clusterRecoverselectInstancesFiredTriggerRecords
updateTriggerStatesForJobFromOtherState
storeTrigger
deleteFiredTriggers
selectFiredTriggerRecords
removeTrigger
deleteSchedulerState集群有结点faied,让JOB能重新执行。executeInLock
数据库集群里等同于
executeInNonManagedTXLockstoreJobAndTriggerupdateJobDetail insertJobDetail
triggerExists
selectJobDetail
updateTrigger insertTrigger保存JOB和TRIGGER配置storeJob 保存JOBremoveJob 删除JOBremoveJobs 批量删除JOBremoveTriggers 批量删除triggersstoreJobsAndTriggers 保存JOB和多个trigger配置removeTrigger 删除triggerreplaceTrigger 替换triggerstoreCalendar 保存定时日期removeCalendar 删除定时日期clearAllSchedulingData 清除所有定时数据pauseTrigger 停止触发器pauseJob 停止任务pauseJobs 批量停止任务resumeTrigger 恢复触发器resumeJob 恢复任务resumeJobs 批量恢复任务pauseTriggers 批量停止触发器resumeTriggers 批量恢复触发器pauseAll 停止所有resumeAll 恢复所有
---
2、STATE_TRIGGER
实现都在JobStoreSupport类
加锁类型加锁方法底层数据库操作备注obtainLockdoCheckinclusterCheckIn判断集群状态
先用LOCK_STATE_ACCESS锁集群状态
再用LOCK_TRIGGER_ACCESS恢复集群运行
---
其中,QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,其表结构如下:
点击(此处)折叠或打开
- --QRTZ_LOCKS表结构
- CREATE TABLE `QRTZ_LOCKS` (
- `LOCK_NAME` varchar(40) NOT NULL,
- PRIMARY KEY (`LOCK_NAME`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- --QRTZ_LOCKS记录
- +-----------------+
- | LOCK_NAME |
- +-----------------+
- | CALENDAR_ACCESS |
- | JOB_ACCESS |
- | MISFIRE_ACCESS |
- | STATE_ACCESS |
- | TRIGGER_ACCESS |
- +-----------------+
可以看出QRTZ_LOCKS中有5条记录,代表5把锁,分别用于实现多个Quartz Node对Job、Trigger、Calendar访问的同步控制。
关于行锁的机制:
1、mysql > set autocommit=0; //先把mysql设置为不自动提交。
2、 select * from es_locks where lock_name = 'TRIGGER_ACCESS' for update ; //线程一通过for update 可以把这行锁住
3、 select * from es_locks where lock_name = 'TRIGGER_ACCESS' for update ; //线程二通过for update 无法获得锁,线程等待。
4、commit; //线程一通过commit 释放锁
5、 //线程二可以访问到数据,线程不再等待。
所以,通过这个机制,一次只能有一个线程来操作 加锁 - 操作 - 释放锁。 如果 操作 的时间过长的话,会带来集群间的主线程等待。
数据库行锁是一种悲观锁,锁表时其它线程无法查询。
源码中关于数据库集群加锁的方法有如下几种:
1、executeInNonManagedTXLock方法的含义是自己管理事务,不让容器管理事务的加锁方法。
点击(此处)折叠或打开
- executeInNonManagedTXLock(
- String lockName,
- TransactionCallback<T> txCallback , final TransactionValidator<T> txValidator )
txCallback是加锁后再回调的方法。
txValidator是验证方法,一般为null
函数先执行加锁,再回调要操作的方法,然后再解锁。
看一下源码:
点击(此处)折叠或打开
- if (lockName != null) {
- // If we aren't using db locks, then delay getting DB connection
- // until after acquiring the lock since it isn't needed.
- if (getLockHandler().requiresConnection()) {
- conn = getNonManagedTXConnection();
- }
-
- transOwner = getLockHandler().obtainLock(conn, lockName);
- }
-
- if (conn == null) {
- conn = getNonManagedTXConnection();
- }
-
- final T result = txCallback.execute(conn);
- try {
- commitConnection(conn);
- } catch (JobPersistenceException e) {
- rollbackConnection(conn);
- if (txValidator == null || !retryExecuteInNonManagedTXLock(lockName, new TransactionCallback<Boolean>() {
- @Override
- public Boolean execute(Connection conn) throws JobPersistenceException {
- return txValidator.validate(conn, result);
- }
- })) {
- throw e;
- }
- }
- Long sigTime = clearAndGetSignalSchedulingChangeOnTxCompletion();
- if(sigTime != null && sigTime >= 0) {
- signalSchedulingChangeImmediately(sigTime);
- }
-
- return result;
- } catch (JobPersistenceException e) {
- rollbackConnection(conn);
- throw e;
- } catch (RuntimeException e) {
rollbackConnection(conn);
throw new JobPersistenceException("Unexpected runtime exception: "
+ e.getMessage(), e);
} finally {
try {
releaseLock(lockName, transOwner);
} finally {
cleanupConnection(conn);
}
}
2、如果不是通过这种回调方法的加锁,一般是:
getLockHandler().obtainLock
执行
commitConnection(conn)
releaseLock
cleanupConnection
二、源码分析锁
目前代码中行锁只用到了STATE_ACCESS 和TRIGGER_ACCESS 这两种。
1、TRIGGER_ACCESS先了解一篇文章,通过源码来分析quartz是如何通过加锁来实现集群环境,触发器状态的一致性。
http://www.360doc.com/content/14/0926/08/15077656_412418636.shtml
可以看到触发器的操作主要用主线程StdScheduleThread来完成,不管是获取需要触发的30S内的触发器,还是触发过程。select和update触发器表时
都会先加锁,后解锁。如果数据库资源竞争比较大的话,锁会影响整个性能。可以考虑将任务信息放在分布式内存,如redis上进行处理。数据库只是定时从redis上load数据下来做统计。
参考:quartz详解2:quartz由浅入深 查看第四章第1,2节
实现都在JobStoreSupport类
加锁类型加锁方法底层数据库操作备注executeInNonManagedTXLockacquireNextTriggerselectTriggerToAcquire
selectTrigger
selectJobDetail
insertFiredTrigger查询需要点火的trigger
选择需要执行的trigger加入到fired_trigger表for执行 triggerFiredselectJobDetail
selectCalendar
updateFiredTrigger
triggerExists updateTrigger点火trigger
修改trigger状态为可执行状态。recoverJobsupdateTriggerStatesFromOtherStates
hasMisfiredTriggersInState doUpdateOfMisfiredTrigger
selectTriggersForRecoveringJobs
selectTriggersInState
deleteFiredTriggers非集群环境下重新执行
failed与misfired的triggerretryExecuteInNonManagedTXLockreleaseAcquiredTriggerupdateTriggerStateFromOtherState
deleteFiredTrigger异常情况下重新释放trigger到初使状态。triggeredJobCompleteselectTriggerStatus
removeTrigger updateTriggerState
deleteFiredTrigger触发JOB任务完成后的处理。obtainLockrecoverMisfiredJobshasMisfiredTriggersInState doUpdateOfMisfiredTrigger重新执行misfired的trigger
可以在启动时执行,也可以由misfired线程定期执行。clusterRecoverselectInstancesFiredTriggerRecords
updateTriggerStatesForJobFromOtherState
storeTrigger
deleteFiredTriggers
selectFiredTriggerRecords
removeTrigger
deleteSchedulerState集群有结点faied,让JOB能重新执行。executeInLock
数据库集群里等同于
executeInNonManagedTXLockstoreJobAndTriggerupdateJobDetail insertJobDetail
triggerExists
selectJobDetail
updateTrigger insertTrigger保存JOB和TRIGGER配置storeJob 保存JOBremoveJob 删除JOBremoveJobs 批量删除JOBremoveTriggers 批量删除triggersstoreJobsAndTriggers 保存JOB和多个trigger配置removeTrigger 删除triggerreplaceTrigger 替换triggerstoreCalendar 保存定时日期removeCalendar 删除定时日期clearAllSchedulingData 清除所有定时数据pauseTrigger 停止触发器pauseJob 停止任务pauseJobs 批量停止任务resumeTrigger 恢复触发器resumeJob 恢复任务resumeJobs 批量恢复任务pauseTriggers 批量停止触发器resumeTriggers 批量恢复触发器pauseAll 停止所有resumeAll 恢复所有
---
2、STATE_TRIGGER
实现都在JobStoreSupport类
加锁类型加锁方法底层数据库操作备注obtainLockdoCheckinclusterCheckIn判断集群状态
先用LOCK_STATE_ACCESS锁集群状态
再用LOCK_TRIGGER_ACCESS恢复集群运行
---
阅读全文
0 0
- quartz详解3:quartz数据库集群-锁机制
- quartz详解3:quartz数据库集群-锁机制
- quartz学习2:quartz数据库集群-锁机制
- quartz 集群
- quartz集群
- quartz集群
- quartz集群
- quartz集群
- quartz集群
- spring 集成quartz 用数据库实现quartz的集群
- quartz 详解
- quartz 详解
- quartz详解
- Quartz详解
- quartz详解2:quartz由浅入深
- Quartz详解之quartz基本概念
- quartz详解2:quartz由浅入深
- quartz详解2:quartz由浅入深
- qt批量插入数据
- 单链表的基本操作(创建、插入、删除......)
- Effective Java 对于所用对象都通用的方法 10.始终要覆盖toString,玩转toString
- Ubuntu 16.04 修改时区!
- intent.putExtra()方法参数详解
- quartz详解3:quartz数据库集群-锁机制
- 基于NDK开发完JNI代码后,Android studio中引入对应的so文件的方法
- angular4实战一项目创建
- 使用VMWare WorkStation安装Linux Mint
- Apache Maven 概述、环境配置
- Spring 注释 @Autowired 和@Resource 的区别
- LeetCode[1]Two Sum
- Sublime Text 3 实用快捷键总结
- REVIEWBOARD 使用说明和强制review的配置方法