使用MongoDB作为Quartz JobStore

Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。你可以到 http://www.quartz-scheduler.org/站点下载 Quartz 的发布版本及其源代码。目前最新的版本是2.2.1。

作为一个优秀的开源调度框架,Quartz 具有以下特点:

  • 强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
  • 灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;
  • 分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。本文暂不讨论该部分内容

另外,作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成。

下面是Quartz中的一些术语:

  • scheduler: 任务调度器
  • trigger: 触发器,用于定义任务调度时间规则
  • job: 任务,即被调度的任务
  • misfire: 错过的,指本来应该被执行但实际没有被执行的任务调度

JobStore负责保存Quartz Scheduler的工作数据, 所以当你的程序重启时,或者在分布式的环境下, 你的应用程序都可以通过这些数据触发事件。 你要基于你的应用程序选择合适的JobStore, 首先你必须要了解各个JobStore, 之后才能容易的选择JobStore。 Quartz框架本身提供了几种JobStore:

  • RAMJobStore
    最简单有效的一个JobStore。它将数据保存在内存中, 所以快是它的特点。缺点是当程序重启时,内存中的数据丢失了,也就是quartz的所有的工作数据都必须重建。
    在属性文件中配置此JobStore:
1
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
  • JDBCJobStore
    恰如其名, 此JobStore使用关系型数据库保存Quartz的工作数据。由于需要读取数据库,它可能不如RAMJobStore那么快,但是能够持久化数据。程序重启时可以恢复Quartz。
    各种主流的数据库都支持,如mysql, oracle, sql server,db2, postgresql, hsql等。
    在属性文件中配置此JobStore:
1
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
  • TerracottaJobStore
    使用Terracotta server存储数据。性能介于前两者之间。
    在属性文件中配置此JobStore:
1
org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore

此外还有一些第三方的JobStore,使用Nosql持久化数据。 比如redis-quartz, 还有这篇文章介绍的quartz-mongodb.

  • quartz-mongodb
    使用MongoDB持久化数据,JDBC中的表正好可以和MongoDB的collection相对应。
    你需要在pom.xml中加入此库:
1
2
3
4
5
<dependency>
<groupId>com.novemberain</groupId>
<artifactId>quartz-mongodb</artifactId>
<version>1.8.0</version>
</dependency>

配置quartz的属性:

1
2
3
4
5
6
7
8
9
10
11
12
# Use the MongoDB store
org.quartz.jobStore.class=com.novemberain.quartz.mongodb.MongoDBJobStore
# MongoDB URI (optional if 'org.quartz.jobStore.addresses' is set)
org.quartz.jobStore.mongoUri=mongodb://localhost:27020
# comma separated list of mongodb hosts/replica set seeds (optional if 'org.quartz.jobStore.mongoUri' is set)
org.quartz.jobStore.addresses=host1,host2
# database name
org.quartz.jobStore.dbName=quartz
# Will be used to create collections like mycol_jobs, mycol_triggers, mycol_calendars, mycol_locks
org.quartz.jobStore.collectionPrefix=mycol
# thread count setting is ignored by the MongoDB store but Quartz requries it
org.quartz.threadPool.threadCount=1

如果你使用Quartzite (quartz for Clojure), 需要配置JobStore如下:

1
org.quartz.jobStore.class=com.novemberain.quartz.mongodb.DynamicMongoDBJobStore

但是quartz-mongodb有一个很大的限制,就是不支持 Quartz 集群。
注意这里的集群是指quartz集群,不是MongoDB集群。

这一特性的缺乏相当致命, 毕竟大部分的Quartz应用还是集群模式。为了支持Quartz集群,你需要扩展,通过在MongogDB建立一个Lock collection,或者通过ZooKeeper的分布式锁等方式确保只有一个节点能获得锁,这样就可以实现Quartz集群。你可以参考JDBC-JobStoreCMT的实现。

1
org.quartz.jobStore.selectWithLockSQL = "SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE"

This Quartz store strives to be feature complete but currently has limitations:

  • Clustering is not supported
    Note that despite Quartz clustering not being supported it is perfectly possible to use Quartz MongoDB store with a MongoDB cluster.