quartz学习四--存储、集群

原创 2016年06月01日 15:31:29
一、Quartz的存储和持久化
    1、存储机制
       Quartz 用 JobStores 对 Job、Trigger、calendar 和 Schduler 数据提供一种存储机制。

       Scheduler 应用已配置的JobStore 来存储和获取到部署信息,并决定正被触发执行的 Job 的职责。

       所有的关于哪个 Job 要执行和以什么时间表来执行他们的信息都来存储在 JobStore。

    2、存储类型
       内存(非持久化) 存储

       持久化存储

    3、JobStore 接口
       (1)、作用
            所有的Job存储机制,不管是在哪里或是如何存储他们的信息的,都必须实现这个接口。

       (2)、JobStore 接口的 API 分类
            Job 相关的 API

            Trigger 相关的 API

            Calendar 相关的 API

            Scheduler 相关的 API

    4、内存(非持久化) JobStore
       (1)、org.quartz.simple.RAMJobStore
            a、作用
           使用内存来存储 Scheduler 信息 , 是 Quartz 的默认的解决方案。

            b、优势
           RAMJobStore是配置最简单的 JobStore:默认已经配置好了。见 quartz.jar:org.quartz.quartz.properties

           RAMJobStore的速度非常快。所有的 quartz存储操作都在计算机内存中

    5、持久化 JobStore
       (1)、组成
            持久化 JobStore = JDBC + 关系型数据库

       (2)、org.quartz.impl.jdbcjobstore.JobStoreSupport 类
            Quartz 所有的持久化的 JobStore 都扩展自 JobStoreSupport 类。

       (3)、JobStoreSupport实现类
            a、每一个设计为针对特定的数据库环境和配置

            b、org.quartz.impl.jdbcjobstore.JobStoreTX
           类设计为用于独立环境中。这里的 "独立",我们是指这样一个环境,在其中不存在与应用容器的事务集成。

            c、org.quartz.impl.jdbcjobstore.JobStoreCMT
           类设计为与程序容器事务集成,容器管理的事务(Container Managed Transactions (CMT))

            d、JobStore 配置
           #properties配置
           org.quartz.jobStore.class = org.quartz.ompl.jdbcjobstore.JobStoreTX

       (4)、数据库结构 -- 表名描述
            QRTZ_CALENDARS                    --->        以 Blob 类型存储 Quartz 的 Calendar 信息
            QRTZ_CRON_TRIGGERS                    --->        存储 Cron Trigger,包括 Cron 表达式和时区信息
            QRTZ_FIRED_TRIGGERS                    --->        存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
            QRTZ_PAUSED_TRIGGER_GRPS                --->        存储已暂停的 Trigger 组的信息
            QRTZ_SCHEDULER_STATE                --->        存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)
            QRTZ_LOCKS                        --->        存储程序的悲观锁的信息(假如使用了悲观锁)
            QRTZ_JOB_DETAILS                    --->        存储每一个已配置的 Job 的详细信息
            QRTZ_JOB_LISTENERS                    --->        存储有关已配置的 JobListener 的信息
            QRTZ_SIMPLE_TRIGGERS                --->        存储简单的 Trigger,包括重复次数,间隔,以及已触的次数
            QRTZ_BLOG_TRIGGERS                    --->        Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
            QRTZ_TRIGGER_LISTENERS                --->        存储已配置的 TriggerListener 的信息
            QRTZ_TRIGGERS                    --->        存储已配置的 Trigger 的信息

            注: 所有的表默认以前缀QRTZ_开始。
             可以通过在 quartz.properties 配置修改(org.quartz.jobStore.tablePrefix = QRTZ_)。

             可以对不同的Scheduler实例使用多套的表,通过改变前缀来实现。

       (5)、优化 quartz数据表结构
            a、对关键查询路径字段建立索引
           create index idx_qrtz_t_next_fire_time on QRTZ_TRIGGERS(NEXT_FIRE_TIME);
           create index idx_qrtz_t_state on QRTZ_TRIGGERS(TRIGGER_STATE);
           create index idx_qrtz_t_nf_st on QRTZ_TRIGGERS(TRIGGER_STATE,NEXT_FIRE_TIME);
           create index idx_qrtz_ft_trig_group on QRTZ_FIRED_TRIGGERS(TRIGGER_GROUP);
           create index idx_qrtz_ft_trig_name on QRTZ_FIRED_TRIGGERS(TRIGGER_NAME);
           create index idx_qrtz_ft_trig_n_g on QRTZ_FIRED_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP);
           create index idx_qrtz_ft_trig_inst_name on QRTZ_FIRED_TRIGGERS(INSTANCE_NAME);
           create index idx_qrtz_ft_job_name on QRTZ_FIRED_TRIGGERS(JOB_NAME);
           create index idx_qrtz_ft_job_group on QRTZ_FIRED_TRIGGERS(JOB_GROUP);

            b、根据Mysql innodb表结构特性,调整主键,降低二级索引的大小
           ALTER TABLE QRTZ_TRIGGERS
           ADD UNIQUE KEY IDX_NAME_GROUP(TRIGGER_NAME,TRIGGER_GROUP),
           DROP PRIMARY KEY,
           ADD ID INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
           ADD PRIMARY KEY (ID);
           ALTER TABLE QRTZ_JOB_DETAILS
           ADD UNIQUE KEY IDX_NAME_GROUP(JOB_NAME,JOB_GROUP),
           DROP PRIMARY KEY,
           ADD ID INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
           ADD PRIMARY KEY (ID);

二、Quartz集群
    1、前提
       只有使用持久的JobStore才能完成Quqrtz集群

    2、结构图
       一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。
       需要分别对每个节点分别启动或停止。不像应用服务器的集群,独立的 Quartz 节点并不与另一个节点或是管理节点通信。
       Quartz 应用是通过数据库表来感知到另一应用。

    3、配置集群
       <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
       <!-- 集群配置 -->
       <prop key="org.quartz.jobStore.isClustered">true</prop>
       <prop key="org.quartz.jobStore.clusterCheckinInterval">15000</prop>
       <prop key="org.quartz.jobStore.maxMisfiresToHandleAtATime">1</prop>
       <!-- 数据源配置 使用DBCP连接池 数据源与dataSource一致 -->
       <prop key="org.quartz.jobStore.dataSource">myDS</prop>
       <prop key="org.quartz.dataSource.myDS.driver">${database.driverClassName}</prop>
       <prop key="org.quartz.dataSource.myDS.URL">${database.url}</prop>
       <prop key="org.quartz.dataSource.myDS.user">${database.username}</prop>
       <prop key="org.quartz.dataSource.myDS.password">${database.password}</prop>
       <prop key="org.quartz.dataSource.myDS.maxConnections">5</prop>

    4、配置解释
       (1)、org.quartz.jobStore.class=JobStoreTX
            将任务持久化到数据中。因为集群中节点依赖于数据库来传播Scheduler实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。

       (2)、org.quartz.jobStore.isClustered=true
            通知Scheduler实例要它参与到一个集群当中。

       (3)、org.quartz.jobStore.clusterCheckinInterval
            定义了Scheduler 实例检入到数据库中的频率(单位:毫秒)。

            Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。

            通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)

二、集群实现分析
    1、Quartz源码分析:
       (1)、原理
            基于数据库表锁实现多Quartz_Node 对Job,Trigger,Calendar等同步机制

       (2)、数据库锁定表 -- QRTZ_LOCKS
            -- 数据库锁定表
            CREATE TABLE `QRTZ_LOCKS` (
              `LOCK_NAME` varchar(40) NOT NULL,
              PRIMARY KEY (`LOCK_NAME`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

            -- 记录
            +-----------------+
            | LOCK_NAME       |
            +-----------------+
            | CALENDAR_ACCESS |
            | JOB_ACCESS      |
            | MISFIRE_ACCESS  |
            | STATE_ACCESS    |
            | TRIGGER_ACCESS  |
            +-----------------+

       (3)、org.quartz.impl.jdbcjobstore.StdRowLockSemaphore   (继承 于 org.quartz.impl.jdbcjobstore.DBSemaphore)
            a、作用
           通过行级别锁实现多节点处理

            b、常量SQL -- 锁定SQL语句
           public static final String SELECT_FOR_LOCK = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_LOCKS + " WHERE " + COL_LOCK_NAME + " = ? FOR UPDATE";

            c、继承方法( 源至 org.quartz.impl.jdbcjobstore.DBSemaphore)
           获取QRTZ_LOCKS行级锁            ---->        public boolean obtainLock(Connection conn, String lockName)

           释放QRTZ_LOCKS行级锁            ---->        public void releaseLock(Connection conn, String lockName)

            d、核心方法
           指定锁定SQL                ---->        protected void executeSQL(Connection conn, String lockName, String expandedSQL)

       (5)、org.quartz.impl.jdbcjobstore.JobStoreTX
            a、作用
           控制并发代码,自身管理事务!

            b、继承方法( 源至 org.quartz.impl.jdbcjobstore.JobStoreSupport)
           /**
            * 执行给定的回调任选具有获得性给定的锁。
            * @param lockName
            */
            protected Object executeInNonManagedTXLock(String lockName, TransactionCallback txCallback) throws JobPersistenceException {
                boolean transOwner = false;
                Connection conn = null;
                try {
                    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();
                    }
                    //回调需要执行的sql语句如:(更新Trigger为运行中(ACQUIRED),删除执行过的Trigger等)
                    Object result = txCallback.execute(conn);
                    //JobStoreTX自身维护事务
                    commitConnection(conn);
                    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(conn, lockName, transOwner);
                    } finally {
                        cleanupConnection(conn);
                    }
                }
            }

            c、核心方法
           protected Object executeInLock(String lockName, TransactionCallback txCallback) throws JobPersistenceException {
               return executeInNonManagedTXLock(lockName, txCallback);
           }

       (6)、JobStoreCMT
            a、作用
           控制并发代码,事务交由容器管理!

            b、核心方法
            /**
             * 执行具有选择性的收购给锁定的回调。
             */
            protected Object executeInLock(String lockName, TransactionCallback txCallback) throws JobPersistenceException {
                boolean transOwner = false;
                Connection conn = null;
                try {
                    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 = getConnection();
                        }
                        transOwner = getLockHandler().obtainLock(conn, lockName);
                    }

                    if (conn == null) {
                        conn = getConnection();
                    }
                    //没有事务提交操作,与任务共享一个事务
                    return txCallback.execute(conn);
                } finally {
                    try {
                        releaseLock(conn, LOCK_TRIGGER_ACCESS, transOwner);
                    } finally {
                        cleanupConnection(conn);
                    }
                }
            }


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

quartz集群调度

  • 2017-02-13 21:39
  • 706KB
  • 下载

spring3+quartz1.6.4 集群示例

  • 2016-09-20 16:49
  • 5.07MB
  • 下载

【Ceph学习之一】Centos7上部署Ceph存储集群以及CephFS的安装

Ceph已然成为开源社区极为火爆的分布式存储开源方案,最近需要调研Openstack与Ceph的融合方案,因此开始了解Ceph,当然从搭建Ceph集群开始。         我搭建机器使用了6台虚拟...

heartbeat(四)heartbeat v2 crm 及 NFS共享存储的mysql高可用集群

下面将用heartbeat v2 crm配置NFS共享存储的mysql高可用集群,NFS下层为LVM,并测试:hb_gui配置的heartbeat crm提供了高可用功能,同时该mysql高可用集群使...
  • tjiyu
  • tjiyu
  • 2016-09-27 23:41
  • 2147

Quartz 1.8.5 集群

  • 2012-11-19 16:01
  • 16KB
  • 下载

Spring4+Quartz2计划任务集群

项目中经常需要计划任务来定时处理一些事情,Quartz是javaEE项目最常见的计划任务组件,Quartz本身支持集群,和spring结合很容易实现计划任务的配置,但是默认spring的Quartz配...

Quartz集群配置和示例源码

  • 2012-04-02 21:14
  • 23.09MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)