Hazelcast集群异常:两个实例Map条目添加不一致
排查Hazelcast实例Map写入异常:实例1重复写入、实例2无写入的问题
问题概述
两个应用实例启动时,需各自将自身主机信息写入名为hosts的Hazelcast Map,但出现异常:
- 实例1写入了自身+实例2的两条主机条目
- 实例2未写入任何条目
已确认:
- 两实例使用完全相同的写入代码:
HazelcastInstance hz = Hazelcast.newHazelcastInstance(); IMap<String, Void> set = hz.getMap("hosts"); set.set(host, Void, ttl, TimeUnit.SECONDS); - 各实例获取的
host值均正确 - 集群组建正常,两实例在管理中心可见
hostsMap已创建,实例1贡献2条条目,实例2贡献0条
排查方向与验证步骤
1. 检查代码执行逻辑是否重复/异常
- 验证实例1的写入触发次数:在实例1的写入代码前后添加日志(如
System.out.println("Writing host: " + host)),确认是否触发了两次写入,且第二次写入的host值为实例2的主机名。 - 修正参数错误:代码中
set.set(host, Void, ...)的第二个参数应为null(而非Void类对象),虽然这通常不会导致写入异常,但可能引发未预期的序列化/存储行为,建议修正为set.set(host, null, ttl, TimeUnit.SECONDS)后重试。 - 确认实例2的写入代码是否执行:在实例2的写入流程中添加日志,检查是否走到
set.set步骤,是否存在线程阻塞、初始化逻辑未触发(如Spring Bean未正确初始化、启动钩子未执行)的情况。
2. 排查Hazelcast集群事件与监听逻辑
- 检查成员事件监听:确认实例1是否注册了
MembershipListener,若在memberAdded事件中写入了新加入实例的主机名,会导致实例1在实例2加入时额外写入一条实例2的条目,而实例2自身的写入可能因某种原因失败。 - 检查Map的拦截器/监听器:查看是否为
hostsMap配置了EntryInterceptor或EntryListener,若监听器逻辑中存在重复写入的逻辑,可能导致实例1触发额外写入。
3. 验证集群时序与分区配置
- 单独启动实例2:仅启动实例2,确认其是否能正常写入自身主机条目到
hostsMap,排除实例2自身的写入能力问题。 - 交换启动顺序:先启动实例2,再启动实例1,观察条目写入情况。若实例2写入自身条目、实例1写入自身条目,说明异常与启动时序相关——可能实例2在首次启动时集群未完全就绪,导致写入失败,而实例1在实例2加入时通过事件触发了额外写入。
- 检查Map分区分布:在Hazelcast管理中心查看
hostsMap的分区分配,确认实例2是否负责了部分分区。若实例2未分配到任何分区,其写入请求会被路由到实例1,但通常不会导致实例2自身写入失败。
4. 日志与深度调试
- 开启Hazelcast DEBUG日志:开启
com.hazelcast.map、com.hazelcast.cluster包的DEBUG级日志,查看:- 实例1是否有两次
PUT请求的日志记录,对应不同的主机名 - 实例2是否发起了
PUT请求,以及是否有错误响应(如HazelcastInstanceNotActiveException、分区不可用等)
- 实例1是否有两次
- 检查实例2的JVM状态:确认实例2是否存在内存不足、线程死锁等问题,导致初始化代码未完成执行。
内容的提问来源于stack exchange,提问作者Usama Zaheer
相关产品推荐
相关产品推荐

