如何优雅地处理成千上万的Quartz失火



我们有一个应用程序需要

  1. 夜间重新处理大量数据,以及

  2. 根据需要重新处理大量数据。

在这两种情况下,大约有10000个石英工作产生并运行。在夜间的情况下,我们有一个石英cron作业,它产生了10000个作业,每个作业单独处理数据。

我们面临的问题是,我们运行的线程约为30个,因此石英作业自然会失败,并继续失败,直到所有作业都得到处理。处理过程可能需要长达6个小时。这10000个作业中的每一个都属于一个特定的域对象,该对象可以并行处理并且完全独立。10000个工作中的每一个都可能需要不同的时间(从半秒到一分钟)。

我的问题是:

  1. 有更好的方法吗?

  2. 如果没有,我们安排/设置石英工作的最佳方式是什么,以便花费最少的时间来研究和处理缺火?

关于or体系结构的注意事项:我们正在运行两个集群,每个集群有三个节点。quartz的版本有点旧(2.0.1),并且在quartz.properties文件中启用了集群。

在这两种情况下,大约有10000个石英工作产生

无需生成新的石英作业Quartz是一个调度器,而不是任务管理器。

在夜间重新处理中,您只需要一个石英cron作业就可以调用一些负责管理和运行10000个任务的服务。在"随需应变"的情况下,石英根本不应该参与。直接调用该服务即可。

该服务如何管理10000项任务

通常,当只有一个JVM可用时,您只需要使用一些ExecutorService。在这里,由于您的手指下有6个节点,因此可以轻松使用Hazelcast。Hazelcast是一个java库,它使您能够对节点进行集群,从而高效地相互共享资源。Hazelcast有一个简单的解决方案来分发ExecutorService,它被称为分布式执行器服务。这就像创建一个HazelcastExecutorService并提交所有成员的任务一样简单。以下是文档中关于在单个成员上调用的示例:

Callable<String> task = new Echo(input); // Echo is just some Callable
HazelcastInstance hz = Hazelcast.newHazelcastInstance();
IExecutorService executorService = hz.getExecutorService("default");
Future<String> future = executorService.submitToMember(task, member);
String echoResult = future.get();

我会通过使用队列(RabbitMQ/ActiveMQ)来实现这一点。cron作业(或任何您的按需触发器)用表示10000条工作指令(即,为给定域对象重新处理数据的指令)的消息填充队列。

在每个节点上,您都有一个执行器池,这些执行器从队列中提取并执行工作指令。这种解决方案意味着,当队列中仍有工作项时,每个执行器都尽可能繁忙,这意味着整个处理将尽快完成。

最好的方法是使用Quartz实例集群。这将在许多群集节点之间共享作业:http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJDBCJobStoreClustering

我会使用计划的石英作业来启动10k任务,但它是通过将任务详细信息附加到JMS队列(10k消息)来实现的。该队列由消息驱动的bean(JavaEEEJBDB)监控。MDB可以在集群中的多个节点上同时运行,每个节点可以运行多个实例。。。不要重新发明分布式任务负载:让Java EE来做吧。

最新更新