跨多个服务器的单个作业执行
Posted
技术标签:
【中文标题】跨多个服务器的单个作业执行【英文标题】:Single job execution across multiple servers 【发布时间】:2017-01-01 15:49:53 【问题描述】:我已经设置了多个服务器运行@Schedule
,该@Schedule
运行春季批处理作业,向用户发送电子邮件。我想确保这个作业只有一个实例在多台服务器上运行。
基于this 问题 我已经实现了一些逻辑,看看是否可以仅使用 spring 批处理来解决这个问题。
为了运行作业,我使用以下方法创建了一个辅助类 JobRunner
:
public void run(Job job)
try
jobLauncher.run(job, new JobParameters());
catch (JobExecutionAlreadyRunningException e)
// Check if job is inactive and stop it if so.
stopIfInactive(job);
catch (JobExecutionException e)
...
stopIfInactive
方法:
private void stopIfInactive(Job job)
for (JobExecution execution : jobExplorer.findRunningJobExecutions(job.getName()))
Date createTime = execution.getCreateTime();
DateTime now = DateTime.now();
// Get running seconds for more info.
int seconds = Seconds
.secondsBetween(new DateTime(createTime), now)
.getSeconds();
LOGGER.debug("Job '' already has an execution with id: with age of s",
job.getName(), execution.getId(), seconds);
// If job start time exceeds the execution window, stop the job.
if (createTime.before(now.minusMillis(EXECUTION_DEAD_MILLIS)
.toDate()))
LOGGER.warn("Execution with id: is inactive, stopping",
execution.getId());
execution.setExitStatus(new ExitStatus(BatchStatus.FAILED.name(),
String.format("Stopped due to being inactive for %d seconds", seconds)));
execution.setStatus(BatchStatus.FAILED);
execution.setEndTime(now.toDate());
jobRepository.update(execution);
然后作业由以下所有服务器上运行:
@Scheduled(cron = "$email.cron")
public void sendEmails()
jobRunner.run(emailJob);
这是多服务器设置的有效解决方案吗?如果没有,有什么替代方案?
编辑 1
我做了更多测试 - 设置两个应用程序,每 5 秒运行一次 @Schedule
,使用我创建的帮助程序类启动作业。看来我的解决方案不能解决问题。这是spring批处理使用的batch_job_execution
表中的数据:
job_execution_id | version | job_instance_id | create_time | start_time | end_time | status | exit_code | exit_message | last_updated | job_configuration_location
------------------+---------+-----------------+-------------------------+-------------------------+-------------------------+-----------+-----------+--------------+-------------------------+----------------------------
1007 | 2 | 2 | 2016-08-25 14:43:15.024 | 2016-08-25 14:43:15.028 | 2016-08-25 14:43:16.84 | COMPLETED | COMPLETED | | 2016-08-25 14:43:16.84 |
1006 | 1 | 2 | 2016-08-25 14:43:15.021 | 2016-08-25 14:43:15.025 | | STARTED | UNKNOWN | | 2016-08-25 14:43:15.025 |
1005 | 2 | 2 | 2016-08-25 14:43:10.326 | 2016-08-25 14:43:10.329 | 2016-08-25 14:43:12.047 | COMPLETED | COMPLETED | | 2016-08-25 14:43:12.047 |
1004 | 2 | 2 | 2016-08-25 14:43:10.317 | 2016-08-25 14:43:10.319 | 2016-08-25 14:43:12.03 | COMPLETED | COMPLETED | | 2016-08-25 14:43:12.03 |
1003 | 2 | 2 | 2016-08-25 14:43:05.017 | 2016-08-25 14:43:05.02 | 2016-08-25 14:43:06.819 | COMPLETED | COMPLETED | | 2016-08-25 14:43:06.819 |
1002 | 2 | 2 | 2016-08-25 14:43:05.016 | 2016-08-25 14:43:05.018 | 2016-08-25 14:43:06.811 | COMPLETED | COMPLETED | | 2016-08-25 14:43:06.811 |
1001 | 2 | 2 | 2016-08-25 14:43:00.038 | 2016-08-25 14:43:00.042 | 2016-08-25 14:43:01.944 | COMPLETED | COMPLETED | | 2016-08-25 14:43:01.944 |
1000 | 2 | 2 | 2016-08-25 14:43:00.038 | 2016-08-25 14:43:00.041 | 2016-08-25 14:43:01.922 | COMPLETED | COMPLETED | | 2016-08-25 14:43:01.922 |
999 | 2 | 2 | 2016-08-25 14:42:55.02 | 2016-08-25 14:42:55.024 | 2016-08-25 14:42:57.603 | COMPLETED | COMPLETED | | 2016-08-25 14:42:57.603 |
998 | 2 | 2 | 2016-08-25 14:42:55.02 | 2016-08-25 14:42:55.023 | 2016-08-25 14:42:57.559 | COMPLETED | COMPLETED | | 2016-08-25 14:42:57.559 |
(10 rows)
我也试过@Palcente提供的方法,结果差不多。
【问题讨论】:
你能解释一下在上述情况下什么不起作用吗?您的意思是同时运行同一作业的多个执行? 是的,两台服务器同时启动同一个作业,即使它仍在其中一个节点上运行/启动。 【参考方案1】:Spring Integration 的最新版本添加了一些围绕分布式锁的功能。这确实是您想要用来确保只有一台服务器触发作业(只有获得锁的服务器应该启动作业)的方法。您可以在此处的文档中阅读有关 Spring Integration 锁定功能的更多信息:http://projects.spring.io/spring-integration/
【讨论】:
我在文档或 spring-integration-samples (github.com/spring-projects/spring-integration-samples) 项目中找不到任何使用 java-config 显示此功能的示例。目前我正在考虑创建一个简单的锁表。以上是关于跨多个服务器的单个作业执行的主要内容,如果未能解决你的问题,请参考以下文章
如何在单个 Spark 作业中调用多个 writeStream 操作?