Java 节点关闭时,已复制映射上的Hazelcast唯一ScheduledExecutorService丢失

Java 节点关闭时,已复制映射上的Hazelcast唯一ScheduledExecutorService丢失,java,hazelcast,scheduledexecutorservice,Java,Hazelcast,Scheduledexecutorservice,我正在尝试在多个节点上运行Hazelcast ReplicatedMap以进行缓存。地图将有大约60000个条目,加载/创建条目的成本非常高 地图的条目有时会变得无效,需要更新或删除,或者必须在地图中插入新条目。为此,我考虑了定期更新地图的定期服务 为了防止并发和昂贵的重复创建新条目,应该只有一个重新加载服务 为了测试这一点,我制作了一个小测试用例: public class HazelTest { private ReplicatedMap<Long, Bean> hzMap

我正在尝试在多个节点上运行Hazelcast ReplicatedMap以进行缓存。地图将有大约60000个条目,加载/创建条目的成本非常高

地图的条目有时会变得无效,需要更新或删除,或者必须在地图中插入新条目。为此,我考虑了定期更新地图的定期服务

为了防止并发和昂贵的重复创建新条目,应该只有一个重新加载服务

为了测试这一点,我制作了一个小测试用例:

public class HazelTest {

  private ReplicatedMap<Long, Bean> hzMap;
  private HazelcastInstance instance;

  public HazelTest() {
    instance = Hazelcast.newHazelcastInstance();

    hzMap = instance.getReplicatedMap("UniqueName");
    IScheduledExecutorService scheduler = instance.getScheduledExecutorService("ExecutorService");
    try {
      scheduler.scheduleAtFixedRate(new BeanReloader(), 5, 10, TimeUnit.SECONDS);
    } catch (DuplicateTaskException ex) {
      System.out.println("reloader already running");
    }
  }

  public static void main(String[] args) throws Exception {
    Random random = new Random(System.currentTimeMillis());

    HazelTest test = new HazelTest();
    System.out.println("Start ...");
    long i = 0;
    try {
      while (true) {
        i++;
        Bean bean = test.hzMap.get((long) random.nextInt(1000));
        if (bean != null) {
          if (i % 100000 == 0) {
            System.out.println("Bean: " + bean.toString());
          }
          bean.setName("NewName");
        }
      }
    } finally {
      test.close();
      System.out.println("End.");
    }
  }

  public void close() {
    instance.getPartitionService().forceLocalMemberToBeSafe(5, TimeUnit.SECONDS);

    if (instance.getPartitionService().isLocalMemberSafe()) {
      instance.shutdown();
    } else {
      System.out.println("Error!!!!!");
    }
  }
}
现在,当我在机器上的不同终端上运行此服务时(或通过网络运行,没有任何区别),节点会显示所需的行为:服务一次只在一个节点上运行-当我启动另一个节点时,会出现DuplicateTaskException

但是,当当前执行任务的节点停机时,服务并不总是切换到另一个节点。大约有2/3的几率服务完全丢失,并且无法在剩余的任何节点上运行

现在我的问题是:这种行为正常吗?我必须自己检查服务是否运行,如果是,通过什么api

还是我做错了什么,还有别的方法来实现我的目标?hazelcast复制地图一开始就是正确的吗


编辑:编辑代码,因为我为发布所做的简化不再显示错误

当节点离开且服务未恢复时,日志中没有错误。唯一的日志记录在一个节点上:

Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.TcpIpConnection
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Connection[id=8, /X.X.X.X:5702->/X.X.X.X:54226, endpoint=[X.X.X.X]:5703, alive=false, type=MEMBER] closed. Reason: Connection closed by the other side
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Connecting to /X.X.X.X:5703, timeout: 0, bind-any: true
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Could not connect to: /X.X.X.X:5703. Reason: SocketException[Verbindungsaufbau abgelehnt to address /X.X.X.X:5703]
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Connecting to /X.X.X.X:5703, timeout: 0, bind-any: true
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Could not connect to: /X.X.X.X:5703. Reason: SocketException[Verbindungsaufbau abgelehnt to address /X.X.X.X:5703]
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Connecting to /X.X.X.X:5703, timeout: 0, bind-any: true
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Could not connect to: /X.X.X.X:5703. Reason: SocketException[Verbindungsaufbau abgelehnt to address /X.X.X.X:5703]
Bean: Bean{id=893, name='NewName'}
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Connecting to /X.X.X.X:5703, timeout: 0, bind-any: true
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.InitConnectionTask
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Could not connect to: /X.X.X.X:5703. Reason: SocketException[Verbindungsaufbau abgelehnt to address /X.X.X.X:5703]
Mär 06, 2017 9:54:08 AM com.hazelcast.nio.tcp.TcpIpConnectionMonitor
WARNUNG: [X.X.X.X]:5702 [dev] [3.8] Removing connection to endpoint [X.X.X.X]:5703 Cause => java.net.SocketException {Verbindungsaufbau abgelehnt to address /X.X.X.X:5703}, Error-Count: 5
Mär 06, 2017 9:54:08 AM com.hazelcast.internal.cluster.ClusterService
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Removing Member [X.X.X.X]:5703 - 875ccc3a-dc10-4c21-815a-4b57ae41a6ff
Mär 06, 2017 9:54:08 AM com.hazelcast.internal.cluster.ClusterService
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] 

Members [3] {
        Member [X.X.X.X]:5702 - 0ec92bb9-6330-4a3d-90ac-0ed374fd266c this
        Member [X.X.X.X]:5701 - 0d1a832e-e1e8-4cad-8546-5a97c8c052c3
        Member [X.X.X.X]:5704 - bd18c7f9-892e-430a-b1ab-da740cc7a6c5
}

Mär 06, 2017 9:54:08 AM com.hazelcast.transaction.TransactionManagerService
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Committing/rolling-back alive transactions of Member [X.X.X.X]:5703 - 875ccc3a-dc10-4c21-815a-4b57ae41a6ff, UUID: 875ccc3a-dc10-4c21-815a-4b57ae41a6ff
Mär 06, 2017 9:54:08 AM com.hazelcast.internal.partition.impl.MigrationManager
INFORMATION: [X.X.X.X]:5702 [dev] [3.8] Re-partitioning cluster data... Migration queue size: 204
除最后一行外,其他的基本相同:

INFORMATION: [X.X.X.X]:5701 [dev] [3.8] Committing/rolling-back alive transactions of Member [X.X.X.X]:5703 - 875ccc3a-dc10-4c21-815a-4b57ae41a6ff, UUID: 875ccc3a-dc10-4c21-815a-4b57ae41a6ff

在4个节点(hz1-4.log)上使用调试日志进行了测试运行。节点4获取了时间表。在一次运行之后,我杀死了那个节点(在hz4.log中记录时间戳15:28:50955)。以下是该次运行的四个日志(注意:由于大量日志记录,我只粘贴了时间戳15:28:50955上的日志…)

通过这种设置,我可以可靠地再现故障。我只是用

mvn exec:java -Dexec.mainClass="de.tle.products.HazelTest" -Dnumber=X

其中X是节点的编号(只是log4j conf文件中的一个变量)。在所有四个节点a运行后,杀死当前正在运行该计划的节点,然后该计划将不会在任何剩余节点上运行。

Hi Lasrik,您是否在成员的日志中看到任何异常?我刚刚在本地尝试了上面的代码,随机启动/杀死了成员,任务按预期重新安排。请记住,最多N个(其中N是为ScheduledExecutor配置的备份计数)成员可以同时下降。如果更多,那么任务将丢失。好吧,有趣的事。。在重温我的代码时,我发现我对代码所做的简化(在这里发布)使代码能够正常工作。我将编辑我的帖子并修改代码,以便问题再次出现。你会启动多少个成员,杀死多少个成员,杀死他们的速度有多快?我正在测试最多4个成员。在一次或两次重新加载程序运行后,我杀死运行任务的成员。如果另一个成员赶上了,我会一个接一个地干掉他,跑一两次。事实上,我没有具体的时间安排,但尝试在所需的生产系统中模拟这样的场景,在这种情况下,成员会来来去去去而没有任何保证。虽然我无法在我的环境中复制,但请您在您的成员上启用调试跟踪,并共享所有成员的日志,好吗?作为记录,我尝试了4-6个成员的设置,在一到两个周期后,我杀死了运行任务的成员,一旦它被另一个成员选中,我也杀死了它,直到我只剩下一个成员。这样做了好几次,任务并没有丢失。我可能在做一些不同的事情,也可能是很有活力的事情。不管怎样,调试日志可能会更好地了解这个问题。Hi Lasrik,您在您的日志中看到来自成员的异常吗?我刚刚在本地尝试了上面的代码,随机启动/杀死了成员,任务按预期重新安排。请记住,最多N个(其中N是为ScheduledExecutor配置的备份计数)成员可以同时下降。如果更多,那么任务将丢失。好吧,有趣的事。。在重温我的代码时,我发现我对代码所做的简化(在这里发布)使代码能够正常工作。我将编辑我的帖子并修改代码,以便问题再次出现。你会启动多少个成员,杀死多少个成员,杀死他们的速度有多快?我正在测试最多4个成员。在一次或两次重新加载程序运行后,我杀死运行任务的成员。如果另一个成员赶上了,我会一个接一个地干掉他,跑一两次。事实上,我没有具体的时间安排,但尝试在所需的生产系统中模拟这样的场景,在这种情况下,成员会来来去去去而没有任何保证。虽然我无法在我的环境中复制,但请您在您的成员上启用调试跟踪,并共享所有成员的日志,好吗?作为记录,我尝试了4-6个成员的设置,在一到两个周期后,我杀死了运行任务的成员,一旦它被另一个成员选中,我也杀死了它,直到我只剩下一个成员。这样做了好几次,任务并没有丢失。我可能在做一些不同的事情,也可能是很有活力的事情。无论如何,调试日志可能会更好地了解问题
INFORMATION: [X.X.X.X]:5701 [dev] [3.8] Committing/rolling-back alive transactions of Member [X.X.X.X]:5703 - 875ccc3a-dc10-4c21-815a-4b57ae41a6ff, UUID: 875ccc3a-dc10-4c21-815a-4b57ae41a6ff
mvn exec:java -Dexec.mainClass="de.tle.products.HazelTest" -Dnumber=X