Hazelcast Scheduled Executor 始终在最新成员上启动任务

Hazelcast Scheduled Executor always starts task on newest member

我正在使用 Hazelcast Scheduled Executor Service 以便 运行 仅在一个服务实例上执行特定任务。为了实现这种行为,我们利用 com.hazelcast.scheduledexecutor.TaskUtils.named(java.lang.String, java.lang.Runnable) 装饰器来避免重复任务。

使用的 Hazelcast 依赖项:

implementation "com.hazelcast:hazelcast-all:4.2" 
implementation "com.hazelcast:hazelcast-kubernetes:2.2.2" // DNS Lookup

我们使用一个 hazelcast 集群,每个服务实例有一个成员

代码示例:

public void scheduleTask() {
    IScheduledExecutorService es = hazelcastInstance.getScheduledExecutorService("myScheduledExecutor");
    try {
        es.scheduleAtFixedRate(named("taskName", task)), 0, 30, SECONDS);
    } catch (DuplicateTaskException ex) {
        System.out.println("Task was already scheduled!");
    }
}

以上示例设法部分实现了所需的行为。唯一的问题是每次启动一个新实例时,预定的执行程序都会 运行 该特定实例上的任务。这并不理想,因为我们希望任务执行一次,例如每 6 小时一次。

有什么方法可以配置计划的执行程序,以便它在它启动的原始实例上维护运行任务,并且只有在原始实例出现故障时才转移到另一个实例?

这不是直接可能的,但有一个近似值。

IScheduledExecutorService 没有提供一种方法来为要使用的成员提供排序。

  • 您可以向特定成员提交任务,但如果原始特定成员死亡,这不会故障转移到您选择的成员。
  • ...各种其他选项...
  • 或者您的代码中的选项 scheduleAtFixedRate 将选择一个成员,每次集群大小时这可能是一个不同的成员。它不应该总是最新的,除非巧合。

你可以做的是有一个计划任务,选择一个成员运行一个普通任务。一项任务启动另一项任务。

在计划任务中,run()可以调用hazelcastInstance.getCluster().getMembers()获取集群成员列表。它所需要的只是一些选择成员的逻辑,然后执行 hazelcastInstance.getExecutorService("default").executeOnMember(runnable, member).

您可以选择具有您配置的特定属性的成员。或具有特定IP的会员。也许最简单的是选择最老的,因为直到最老的离开之前这不会改变,在这种情况下,第二个最老的现在是最老的,容易故障转移。

我使用的解决方法是处理已经安排好的任务,并根据上次安排任务的时间计算出初始延迟,然后再次安排。

类似于:

public void scheduleTask() {
    IScheduledExecutorService es = hazelcastInstance.getScheduledExecutorService("myScheduledExecutor");
    try {
        disposePreviousScheduledTasks(es);
        es.scheduleAtFixedRate(named("taskName", task)), initialDelay, 30, SECONDS);
    } catch (DuplicateTaskException ex) {
        System.out.println("Task was already scheduled!");
    }
}