如何使集群仅运行一次任务?


13

如果您有一项任务只想在服务器群集上仅运行一次,那么定期执行此操作的最佳方法是什么?在这种情况下,群集的定义是2台或更多台具有负载均衡器后面的分布式会话的相同服务器。

用例:您有一项运行成本很高的任务,该任务每X小时只能运行一次。例如,此作业可以遍历一堆记录并更新其状态。

  • 最糟糕的情况是,两次运行作业会使您的数据无效。
  • 最好的情况是该作业利用了所有服务器上的资源。

要求摘要:

  1. 即使节点之一关闭,该作业仍必须运行。
  2. 每个计划只能运行一次作业。
  3. 如果在同一时间或重叠时间安排了多个作业,则正在运行的作业数将在服务器之间平均分配。
  4. 机器必须具有相同的代码库,并且必须通过NTP进行同步。
  5. 根据环境变量,节点之间的配置可能有所不同。
  6. 作业必须按时开始或在指定时间的给定间隔内开始。(例如说5分钟)

可能的解决方案

  • 将一个节点设置为主节点,这违反了上面的1,因此无效。
  • 要求负载均衡器平衡以启动该作业。不幸的是,这具有副作用,如果您同时运行多个作业,则它们可能都由同一台机器运行。

这必须在Java的servlet容器中运行。但是,它不是我正在寻找的工作的编码。

当然,这是已知最佳解决方案可以解决的问题。


相关问题。 /programming/5949038/schedule-job-executes-twice-on-cluster

这不是重复的,因为根据上述5个要求,解决方案还不够。最高支持的解决方案存在种族问题,第二种解决方案违反了要求3

Answers:


16

您有共享的数据库吗?我过去使用数据库作为仲裁器来完成此操作。

基本上,每个“作业”在数据库中都表示为一行。您可以通过在数据库中添加一行以及您希望其运行的时间来调度作业,然后每台服务器都可以:

SELECT TOP 1 *
FROM jobs
WHERE state = 'NotRun'
ORDER BY run_time ASC

这样,他们都会选择计划在下一次运行的作业。他们都睡着了,这样他们就可以在工作真正开始时醒来。然后,他们都这样做:

UPDATE jobs
SET state = 'Running'
WHERE job_id = :id
  AND state = 'NotRun'

:id您在上述步骤中获得的工作的标识符在哪里。由于更新是原子更新,因此只有一台服务器会实际更新该行,因此您可以检查数据库的“行数更新”状态码,以确定是否是实际更新过该行的服务器,从而确定是否是服务器可以胜任这项工作。

如果您没有“赢得”并且您没有执行任务,则立即返回步骤1。如果您“赢了”,则安排该作业在另一个线程中执行,然后等待几秒钟再返回到步骤1。这样,这次没有获得该作业的服务器更有可能接一个作业。计划立即运行。


1
您在这里使用什么隔离级别?读已提交或序列化?
Maverick Riz 2015年

2

多个应用服务器具有“集群范围内的单例服务”的功能。

例如,Weblogic具有通过Web管理控制台配置的Singleton Service功能。

您必须编写一个实现weblogic.cluster.singleton.SingletonService的类,并使用它在管理控制台中声明该服务。群集负责实例化类并在服务启动或停止时通知您。SingletonService接口具有activate()和deactivate()方法。

Weblogic首次在群集的一个节点上启动服务时,将调用activate()。如果所选节点出现故障,则管理服务器会在另一台服务器上“移动”服务,并在该服务器上调用activate()。

http://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/taskhelp/clusters/ConfigureSingletonService.html

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.