ZK集群出现网络波动导致一部分provider无法重新注册

问题产生场景:
    Ephermal节点未及时删除导致provider不能恢复注册,在应用日志中,应用重连Zookeeper成功后,provider立刻进行了重新注册,之后便没有打印任何日志。而在ZK日志中,注册节点被删除后,并没有重新创建注册节点。
 

public void register(URL url) {
		super.register(url);
		failedRegistered.remove(url);
		failedUnregistered.remove(url);
		try{
			doRegister(url);
		} catch (Exception e) {
			Throwable t = e;
			boolean check = t instanceof SkipFailbackWrapperException;
			if(check || skipFailback) {
				if(skipFailback) {
					t = t.getCause();
				}
				throw new IllegalStateException("Failed to register " + url + "to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(),t);
			} else {
				logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t);
			}
			failedRegistered.add(url);
		}
	}

Dubbo默认使用curator作为Zookeeper的客户端,curator与ZK是通过session未知链接的。当curator重连ZK时,若session未过期,则继续使用原session重新链接。而Ephemeral节点与session是绑定的关系,在session过期后,会删除此session下的Ephemeral节点。
    继续对doRegister(url)的代码进行进一步排查,发现在CuratorZookeeperClient.createEphemeral(path)方法中有这么一段逻辑:在createEphemeral(path)捕获到了NodeExistsException,创建Ephemeral节点时,若此节点已存在,则认为Ephemeral创建成功。
    但当ZK的session过期与删除Ephemeral节点不是原子性的操作情况下。在客户端得到session过期的消息时,session对应的Ephemeral节点可能还未被ZK删除。此时Dubbo去创建Ephemeral节点,发现节点仍然存在,所以不再创建新节点。当Ephemeral节点被ZK删除后,便会出现Dubbo认为重新注册成功但实际未成功的情况,会导致一部分的provider无法重新注册到ZK上。

public void createEphemeral(String path) {
		try {
			client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
		} catch (NodeExistsException e) {
		} catch (Exception e) {
			throw new IllegalStateException(e.getMessage(), e);
		}
	}


解决方案:
    1.临时方案:手动重启provider。
    2.升级Dubbo版本至2.7.3(需要检测此版本是否与线上环境兼容,目前此版本不与DubboX兼容)
    3.修改源码,当Ephemeral节点捕获到NodeExistsException时,进行判断,若Ephemeral节点的SessionId与当前客户端的SessionId不同,则删除并重建Ephemeral节点。

发布了110 篇原创文章 · 获赞 475 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/yongqi_wang/article/details/103816521
今日推荐