quartz详解3:quartz数据库集群-锁机制
http://blog.itpub.NET/11627468/viewspace-1764753/
其中,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 |
- +-----------------+
注:此表结构在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方法的含义是自己管理事务,不让容器管理事务的加锁方法。
点击(此处)折叠或打开
- executeInNonManagedTXLock(
- String lockName,
- TransactionCallback<T> txCallback , final TransactionValidator<T> txValidator )
三个参数lockName的值是上面所说的TRIGGER_ACCESS,表示要加锁的类型。
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
二、源码分析锁
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数据库集群-锁机制的更多相关文章
- Redis详解(七)——集群
Redis详解(七)--集群 Redis3.0版本之前,可以通过Redis Sentinel(哨兵)来实现高可用 ( HA ),从3.0版本之后,官方推出了Redis Cluster,它的主要用途是 ...
- 详解k8s原生的集群监控方案(Heapster+InfluxDB+Grafana) - kubernetes
1.浅析监控方案 heapster是一个监控计算.存储.网络等集群资源的工具,以k8s内置的cAdvisor作为数据源收集集群信息,并汇总出有价值的性能数据(Metrics):cpu.内存.netwo ...
- 转载:quartz详解:quartz由浅入深
转载网址:http://blog.itpub.net/11627468/viewspace-1763498/ 一.quartz核心概念 先来看一张图: scheduler 任务调度器 ...
- Solr系列二:solr-部署详解(solr两种部署模式介绍、独立服务器模式详解、SolrCloud分布式集群模式详解)
一.solr两种部署模式介绍 Standalone Server 独立服务器模式:适用于数据规模不大的场景 SolrCloud 分布式集群模式:适用于数据规模大,高可靠.高可用.高并发的场景 二.独 ...
- Kafka 详解(二)------集群搭建
这里通过 VMware ,我们安装了三台虚拟机,用来搭建 kafka集群,虚拟机网络地址如下: hostname ipaddress ...
- Zookeeper详解-伪分布式和集群搭建(八)
说到分布式开发Zookeeper是必须了解和掌握的,分布式消息服务kafka .hbase 到hadoop等分布式大数据处理都会用到Zookeeper,所以在此将Zookeeper作为基础来讲解. Z ...
- Redis面试题详解:哨兵+复制+事务+集群+持久化等
Redis主要有哪些功能? 1.哨兵(Sentinel)和复制(Replication) Redis服务器毫无征兆的罢工是个麻烦事,如何保证备份的机器是原始服务器的完整备份呢?这时候就需要哨兵和复制. ...
- 大数据入门第十六天——流式计算之storm详解(三)集群相关进阶
一.集群提交任务流程分析 1.集群提交操作 参考:https://www.jianshu.com/p/6783f1ec2da0 2.任务分配与启动流程 参考:https://www.cnblogs.c ...
- 详解Mysql事务隔离级别与锁机制
一.概述 我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能 就会导致我们说的脏写. 胀读和不可重复读.幻读这些问题. 这些问题的本质都是数据库的多事务并 ...
随机推荐
- Jquery事件汇总、网页入口
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- MQTT 协议学习:001-搭建MQTT通信环境,并抓包测试
背景 目的:了解MQTT 通信的有关概念与流程:方便推算某些数据与文档描述是否一致. 为了能够在保证学习质量的前提下,降低配置环境的门槛,我们将服务器搭建在windwos中,实行内网间的MQTT协议访 ...
- phpMydmin的GetShell思路
phpMyadmin简介 phpMyadmin是一个以PHP为基础的MySQL数据库管理工具,使网站管理员可通过Web接口管理数据库 . 信息收集 此部分主要需要收集的是网站物理路径,否则后续无法通过 ...
- docker学习笔记-03:docker的镜像原理
镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件.它包含运行某个环境所需的所有内容,包括代码.库.环境变量和配置文件. 一.镜像是什么 (一).联合文件系统(Unio ...
- 【蓝桥】第八届C语言C组第7题 Excel地址(进制变形题,stack()简单使用)转载
标题: Excel地址 Excel单元格的地址表示很有趣,它使用字母来表示列号. 比如, A表示第1列, B表示第2列, Z表示第26列, AA表示第27列, AB表示第28列, BA表示第53列, ...
- C++代做,C++编程代做,C++程序代做,留学生C++ Lab代写
C++代做,C++编程代做,C++程序代做 我们主要面向留学生,广泛接美加澳国内港台等地编程作业代写,中英文均可. C语言代写 C++代写 Python代写 Golang代写 Java代写 一年半的时 ...
- gem5-gpu 运行 PARSEC2.1
PARSEC是针对共享内存多核处理器(CPU)的一套基准测试程序,详细介绍见wiki:http://wiki.cs.princeton.edu/index.php/PARSEC,主要参考:http:/ ...
- Spring入门之五-------SpringIoC之通过注解实现
一.准备工作 创建一个Class注解@Configuration,如下例子: @Configuration // 该注解可理解为将当前class等同于一个xml文件 @ComponentScan(&q ...
- JPA#Interfaces总结
_开局一张图,内容全靠编 震惊:某小白熟练使用了JpaRepository和JpaSpecificationExecutor,就在简历上写下了,精通SpringData Jpa. 震惊,如果想熟练的使 ...
- 七十七、SAP中数据库操作之多表联合查询
一.我们看一下SFLIGHT表和SPFLI表,表结构如下 二.这2个表的数据如下 三.我们代码如下 四.多表联合查询结果如下