【发布时间】:2009-07-24 14:02:53
【问题描述】:
我有 4 台服务器,上面安装了 JVM。我编写了一个 java 服务,Quartz 每 10 分钟调用一次该服务。但在 4 台服务器中,每 10 分钟完成 4 次调用。这种情况造成了竞争条件。我只想要 4 个 JVM 上的一项服务。
如何使用 Spring Framework 做到这一点?
【问题讨论】:
标签: java spring quartz-scheduler cluster-computing
我有 4 台服务器,上面安装了 JVM。我编写了一个 java 服务,Quartz 每 10 分钟调用一次该服务。但在 4 台服务器中,每 10 分钟完成 4 次调用。这种情况造成了竞争条件。我只想要 4 个 JVM 上的一项服务。
如何使用 Spring Framework 做到这一点?
【问题讨论】:
标签: java spring quartz-scheduler cluster-computing
这实际上很容易用 Quartz 设置。 Spring 本身在这里无法为您提供太多帮助,因为它不知道正在运行的其他 JVM。另一方面,Quartz 具有集群调度器的概念。
基本上,您需要设置一个所有 4 个 JVM 都可以共享的数据库。这将用作所有 4 个实例的调度程序。调度作业时,它仅由使用集群调度程序的一个实例运行。
取自 Quartz 网站 wiki 进行聚类( http://www.opensymphony.com/quartz/wikidocs/ConfigJDBCJobStoreClustering.html),这是一个关于如何设置集群调度程序的示例配置。如果您以这种方式配置调度程序,也可以直接从 spring 中设置这些属性。
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@polarbear:1521:dev
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = quartz
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
【讨论】:
您的问题不是很清楚,所以让我看看我是否理解您的意思:您有 4 台服务器,每台服务器在 VM 中运行 Quartz,每台服务器都有相同的石英作业,计划每 10 分钟运行一次,使用一个 cron 表达式。每 10 分钟,所有 4 台服务器都会启动相同的工作,从而创建您的竞争条件,因为它们都尝试同时执行相同的操作。
这不是 Spring 的真正工作。但是,Quartz 确实具有集群功能,您可以将作业配置为仅在集群中运行单个服务器。它使用共享数据库来协调哪些服务器运行哪些作业,并确保它们不会一起执行。
文档有一些关于此 here 的信息,但在通常的 opensymphony.com 风格中,它们非常稀疏且无用。
【讨论】:
我在我们的 Web 应用程序中所做的是将每个作业包装在一个类中,该类在整个集群中取出一个全局锁(我使用 memcached,因为我并不关心任务是否过于频繁地运行),并且只有在获得锁时才运行任务。然后它可以在任务完成时释放锁(不要忘记在finally 中执行此操作)。
包装每个作业而不是更改调度程序的一个优点是,您可以让一些作业在所有机器上运行,而另一些只在一台机器上运行。
【讨论】: