我的基于Hazelcast的程序可以在两种模式下工作:提交者和工作者。
提交者通过某个键将一些POJO放入分布式地图,例如:hazelcastInstance.getMap(MAP_NAME).put(key, value);
Worker有一个无限循环(内部有Thread.sleep(1000L);
超时),它必须处理map中的实体。现在我只是在这个循环中打印地图大小。
现在问题就在于此。我开始工作的应用程序然后我同时启动四个提交者(每个提交者都添加一个条目并终止它的工作)。但是在完成所有提交者应用程序之后,工作者应用程序会打印任意大小:有时它会检测到只添加了一个条目,有时是两个,有时是三个(实际上它从未见过所有四个条目)。
这个简单的流程有什么问题?我在Hazelcast文档中读到put()
方法是同步的,所以它保证在它返回后,将条目放在分布式地图上,被复制。但在我的实验中似乎并非如此。
UPD(代码)
者:
public void submit(String key) {
Object mySerializableObject = ...
IMap<String, Object> map = hazelcastInstance.getMap(MAP_NAME);
map.putIfAbsent(key, mySerializableObject, TASK_TTL_IN_HOURS, TimeUnit.HOURS);
}
工人:
public void process() {
while (true) {
IMap<String, Object> map = hazelcastInstance.getMap(MAP_NAME);
System.out.println(map.size());
// Optional<Map.Entry<String, Object>> objectToProcess = getObjectToProcess();
// objectToProcess.ifPresent(objectToProcess-> processObject(id, objectToProcess));
try {
Thread.sleep(PAUSE);
} catch (InterruptedException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
我注释掉了“处理”部分本身,因为现在我只是试图获得地图的一致状态。上面的代码每次打印不同的结果,例如:“4,3,1,1,1,1,1 ......”(因此它甚至可以看到4个提交的任务片刻,但随后它们......消失)
UPD(日志)
工人:
...
tasksMap.size() = 0
tasksMap.size() = 0
tasksMap.size() = 0
tasksMap.size() = 0
tasksMap.size() = 1
tasksMap.size() = 2
tasksMap.size() = 2
tasksMap.size() = 2
tasksMap.size() = 2
tasksMap.size() = 2
...
提交者1:
Before: tasksMap.size() = 0
After: tasksMap.size() = 1
提交者2:
Before: tasksMap.size() = 1
After: tasksMap.size() = 4
提交者3:
Before: tasksMap.size() = 1
After: tasksMap.size() = 2
提交者4:
Before: tasksMap.size() = 3
After: tasksMap.size() = 4
答案 0 :(得分:7)
嗯,我猜,我已经找到了问题所在。据我所知,IMap
返回的分布式hazelcastInstance.getMap
并不能保证数据在群集中的所有现有节点上都被复制:某些部分数据可能会复制到某些节点,另一部分部分 - 到另一个节点。这就是为什么在我的示例中,一些提交的任务不是复制到工作节点(它永久地工作),而是复制到其他提交者,它们在提交后终止执行。所以这些条目在提交者退出时丢失了。
我将hazelcastInstance.getMap
替换为hazelcastInstance.getReplicatedMap
解决了这个问题。此方法返回ReplicatedMap
,AFAIK保证放入其中的条目将复制到群集的所有节点。所以现在一切都在我的系统中运行良好。