排查过程: 在出现服务发现返回的hosts为空的时间点,nacos节点的naming-distro.log日志中出现以下记录,服务s4的数据被清理:
2023-04-10 10:14:25,949 INFO to remove keys: [com.alibaba.nacos.naming.iplist.ephemeral.project-1##env-1@@s4], to update keys: [], source: 10.0.0.2:8848
追踪定位:
日志出现在com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl#onReceiveChecksums中,该方法处理来自集群内其他节点的distro checkSum请求(/v1/ns/distro/checksum)。
查看该方法处理逻辑,发现在集群节点数量发生变更时,有可能会因各个节点更新healthyList速度不一致,导致处理checkSum请求时错误地移除了部分临时服务实例数据。
整理了一张个人猜测的状态流转图(“负责”指该nacos管理的服务(distro responsible),“缓存”指该nacos持有的服务实例数据,“节点”指该nacos持有的healthyList)。在下图【Step5】阶段,查询s4健康实例的服务发现请求发往Nacos3时,返回空数据列表。
问题分析 在DistroConsistencyServiceImpl#onReceiveChecksums处理中,会准备两个List:更新key(toUpdateKeys)、删除key(toRemoveKeys)。在上图的【Step5】阶段中,Nacos2和Nacos3的healthList不一致,两边都认为服务s4应该由自己负责管理,当Nacos3处理Nacos2发送的checkSums请求时,会将服务s4有关的key放入到toRemoveKeys中,同时并不会放入toUpdateKeys中,导致Nacos3上的服务s4实例缓存在一段时间内不存在:
建议
是否可以在DistroConsistencyServiceImpl#onReceiveChecksums方法的删除toRemoveKeys中key之前增加一段二次检查:“若该key的数据版本号与source server的版本号一致,将该key从toRemoveKeys中移除”?