http://blog.itpub.NET/11627468/viewspace-1764753/

一、quartz数据库锁

其中,QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,其表结构如下:

点击(此处)折叠或打开

  1. --QRTZ_LOCKS表结构
  2. CREATE TABLE `QRTZ_LOCKS` (
  3. `LOCK_NAME` varchar(40) NOT NULL,
  4. PRIMARY KEY (`LOCK_NAME`)
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  6. --QRTZ_LOCKS记录
  7. +-----------------+
  8. | LOCK_NAME |
  9. +-----------------+
  10. | CALENDAR_ACCESS |
  11. | JOB_ACCESS |
  12. | MISFIRE_ACCESS |
  13. | STATE_ACCESS |
  14. | TRIGGER_ACCESS |
  15. +-----------------+

注:此表结构在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方法的含义是自己管理事务,不让容器管理事务的加锁方法。

点击(此处)折叠或打开

  1. executeInNonManagedTXLock(
  2. String lockName,
  3. TransactionCallback<T> txCallback , final TransactionValidator<T> txValidator )

三个参数lockName的值是上面所说的TRIGGER_ACCESS,表示要加锁的类型。
txCallback是加锁后再回调的方法。
txValidator是验证方法,一般为null
函数先执行加锁,再回调要操作的方法,然后再解锁。
看一下源码:

点击(此处)折叠或打开

  1. if (lockName != null) {
  2. // If we aren't using db locks, then delay getting DB connection
  3. // until after acquiring the lock since it isn't needed.
  4. if (getLockHandler().requiresConnection()) {
  5. conn = getNonManagedTXConnection();
  6. }
  7. transOwner = getLockHandler().obtainLock(conn, lockName);
  8. }
  9. if (conn == null) {
  10. conn = getNonManagedTXConnection();
  11. }
  12. final T result = txCallback.execute(conn);
  13. try {
  14. commitConnection(conn);
  15. } catch (JobPersistenceException e) {
  16. rollbackConnection(conn);
  17. if (txValidator == null || !retryExecuteInNonManagedTXLock(lockName, new TransactionCallback<Boolean>() {
  18. @Override
  19. public Boolean execute(Connection conn) throws JobPersistenceException {
  20. return txValidator.validate(conn, result);
  21. }
  22. })) {
  23. throw e;
  24. }
  25. }
  26. Long sigTime = clearAndGetSignalSchedulingChangeOnTxCompletion();
  27. if(sigTime != null && sigTime >= 0) {
  28. signalSchedulingChangeImmediately(sigTime);
  29. }
  30. return result;
  31. } catch (JobPersistenceException e) {
  32. rollbackConnection(conn);
  33. throw e;
  34. } 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类

加锁类型 加锁方法 底层数据库操作 备注
executeInNonManagedTXLock acquireNextTrigger selectTriggerToAcquire
selectTrigger
selectJobDetail
insertFiredTrigger
查询需要点火的trigger
选择需要执行的trigger加入到fired_trigger表
for执行 triggerFired selectJobDetail
selectCalendar
updateFiredTrigger
triggerExists updateTrigger
点火trigger
修改trigger状态为可执行状态。
recoverJobs updateTriggerStatesFromOtherStates
hasMisfiredTriggersInState doUpdateOfMisfiredTrigger
selectTriggersForRecoveringJobs
selectTriggersInState
deleteFiredTriggers
非集群环境下重新执行
failed与misfired的trigger
retryExecuteInNonManagedTXLock releaseAcquiredTrigger updateTriggerStateFromOtherState
deleteFiredTrigger
异常情况下重新释放trigger到初使状态。
triggeredJobComplete selectTriggerStatus
removeTrigger   updateTriggerState
deleteFiredTrigger
触发JOB任务完成后的处理。
obtainLock recoverMisfiredJobs hasMisfiredTriggersInState doUpdateOfMisfiredTrigger 重新执行misfired的trigger
可以在启动时执行,也可以由misfired线程定期执行。
clusterRecover selectInstancesFiredTriggerRecords
updateTriggerStatesForJobFromOtherState
storeTrigger
deleteFiredTriggers
selectFiredTriggerRecords
removeTrigger
deleteSchedulerState
集群有结点faied,让JOB能重新执行。
executeInLock
数据库集群里等同于
executeInNonManagedTXLock
storeJobAndTrigger updateJobDetail insertJobDetail
triggerExists
selectJobDetail
updateTrigger insertTrigger
保存JOB和TRIGGER配置
storeJob   保存JOB
removeJob   删除JOB
removeJobs   批量删除JOB
removeTriggers   批量删除triggers
storeJobsAndTriggers   保存JOB和多个trigger配置
removeTrigger   删除trigger
replaceTrigger   替换trigger
storeCalendar   保存定时日期
removeCalendar   删除定时日期
clearAllSchedulingData   清除所有定时数据
pauseTrigger   停止触发器
pauseJob   停止任务
pauseJobs   批量停止任务
resumeTrigger   恢复触发器
resumeJob   恢复任务
resumeJobs   批量恢复任务
pauseTriggers   批量停止触发器
resumeTriggers   批量恢复触发器
pauseAll   停止所有
resumeAll   恢复所有

---

2、STATE_TRIGGER
实现都在JobStoreSupport类

加锁类型 加锁方法 底层数据库操作 备注
obtainLock doCheckin clusterCheckIn 判断集群状态
先用LOCK_STATE_ACCESS锁集群状态
再用LOCK_TRIGGER_ACCESS恢复集群运行
     

---

quartz详解3:quartz数据库集群-锁机制的更多相关文章

  1. Redis详解(七)——集群

    Redis详解(七)--集群 ​Redis3.0版本之前,可以通过Redis Sentinel(哨兵)来实现高可用 ( HA ),从3.0版本之后,官方推出了Redis Cluster,它的主要用途是 ...

  2. 详解k8s原生的集群监控方案(Heapster+InfluxDB+Grafana) - kubernetes

    1.浅析监控方案 heapster是一个监控计算.存储.网络等集群资源的工具,以k8s内置的cAdvisor作为数据源收集集群信息,并汇总出有价值的性能数据(Metrics):cpu.内存.netwo ...

  3. 转载:quartz详解:quartz由浅入深

    转载网址:http://blog.itpub.net/11627468/viewspace-1763498/ 一.quartz核心概念 先来看一张图:         scheduler 任务调度器 ...

  4. Solr系列二:solr-部署详解(solr两种部署模式介绍、独立服务器模式详解、SolrCloud分布式集群模式详解)

    一.solr两种部署模式介绍 Standalone Server 独立服务器模式:适用于数据规模不大的场景 SolrCloud  分布式集群模式:适用于数据规模大,高可靠.高可用.高并发的场景 二.独 ...

  5. Kafka 详解(二)------集群搭建

    这里通过 VMware ,我们安装了三台虚拟机,用来搭建 kafka集群,虚拟机网络地址如下: hostname                      ipaddress             ...

  6. Zookeeper详解-伪分布式和集群搭建(八)

    说到分布式开发Zookeeper是必须了解和掌握的,分布式消息服务kafka .hbase 到hadoop等分布式大数据处理都会用到Zookeeper,所以在此将Zookeeper作为基础来讲解. Z ...

  7. Redis面试题详解:哨兵+复制+事务+集群+持久化等

    Redis主要有哪些功能? 1.哨兵(Sentinel)和复制(Replication) Redis服务器毫无征兆的罢工是个麻烦事,如何保证备份的机器是原始服务器的完整备份呢?这时候就需要哨兵和复制. ...

  8. 大数据入门第十六天——流式计算之storm详解(三)集群相关进阶

    一.集群提交任务流程分析 1.集群提交操作 参考:https://www.jianshu.com/p/6783f1ec2da0 2.任务分配与启动流程 参考:https://www.cnblogs.c ...

  9. 详解Mysql事务隔离级别与锁机制

    一.概述 我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能 就会导致我们说的脏写. 胀读和不可重复读.幻读这些问题. 这些问题的本质都是数据库的多事务并 ...

随机推荐

  1. python学习0day

    一开始学习python没有什么感觉,也没怎么用到,时间间隔大概有一年了开始重新拾起python,话说滋味不太好受,推荐大家学到就常常的练习,不要和小白一样,难受.... 推荐一个网站: 菜鸟教程 - ...

  2. PAN3501与AS3933完美兼容替代

    现在不少校园门禁卡都是采用奥地利的AS3933,市场需求是供不应求,当然价格上还是不断上升趋势.成本上压力也是越来越大,不少厂家在寻找能替代软硬件兼容AS3933的芯片方案.今天我就为大家介绍一款能否 ...

  3. css - flex 定义排列方向

    flex-direction定义伸缩项目放置在伸缩容器的排列方向,对应有四个值: (1)row:从左到右或从右到左 (2)row-reverse:与row属性相反 (3)column:从上到下排列 ( ...

  4. axios 如何取消已发送的请求?

    前言 最近在项目中遇到一个问题,在连续发送同一请求时,如果第二次请求比第一次请求快,那么实际显示的是第一次请求的数据,这就会造成数据和我选择的内容不一致的问题.解决的方案:在后续发送请求时,判断之前的 ...

  5. NoSql相关

    1  NoSQL, No Problem: An Intro to NoSQL Databases https://www.thoughtworks.com/insights/blog/nosql-n ...

  6. SpringBoot-属性文件properties形式

    SpringBoot-属性文件properties形式 上述使用JavaBean的配置可以实现数据源的配置,但是如果配置文件中的内容需要被多次调用就没那么方便了,所以我们学习新的方法,将Propert ...

  7. python scipy样条插值函数大全(interpolate里interpld函数)

    scipy样条插值 scipy样条插值1.样条插值法是一种以可变样条来作出一条经过一系列点的光滑曲线的数学方法.插值样条是由一些多项式组成的,每一个多项式都是由相邻的两个数据点决定的,这样,任意的两个 ...

  8. DIV 透明度 设置

    filter:alpha(opacity=70); -moz-opacity:0.70;-khtml-opacity: 0.70;   opacity: 0.70;

  9. vue-cli 局域网可访问配置

    vue-cli 使用官方脚手架搭建以后,本地的config配置已经没有了,默认打开localhost,无法ip访问 只要修改项目目录配置和防火墙配置 1.在项目根目录下面加一个文件vue.config ...

  10. Day 31:CSS选择器、常用CSS样式、盒子模型

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...