news 2026/7/7 20:07:48

诡异的问题:Dubbo注册zookeeper协议时,竟然出现了这种异常提示

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
诡异的问题:Dubbo注册zookeeper协议时,竟然出现了这种异常提示

遇到一个很诡异的问题,我在启动多个配置相同zookeeper的Dubbo项目时,其他项目都是正常启动,唯独有一个项目在启动过程中,Dubbo注册zookeeper协议时,竟然出现了这样的异常提示——

Caused by: java.lang.IllegalStateException: zookeeper not connected at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:80) ... 79 common frames omitted

我愣了一下,原以为是zookeeper集群挂了,然后检查了一下,都正常啊,奇怪的是,其他系统也是正常连接,为啥会有一台出现了这样的异常呢?

看了一下异常提示,当我深入研究了一下出错的地方时,才恍然明白出现这个异常究竟是为什么了。

可谓是,在源码面前,一切都是裸泳。

先来看异常提示出现的类方法CuratorZookeeperClient,这个方法的作用是建立zookeeper客户端的连接,类似http通信一般,在建立通信前,需要先建立三次握手连接,同理,在zookeeper客户端创建各类节点前,同样需要先建立客户端连接到服务器上——

public CuratorZookeeperClient(URL url) { super(url); try { int timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_CONNECTION_TIMEOUT_MS); int sessionExpireMs = url.getParameter(ZK_SESSION_EXPIRE_KEY, DEFAULT_SESSION_TIMEOUT_MS); CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() .connectString(url.getBackupAddress()) .retryPolicy(new RetryNTimes(1, 1000)) .connectionTimeoutMs(timeout) .sessionTimeoutMs(sessionExpireMs); String authority = url.getAuthority(); if (authority != null && authority.length() > 0) { builder = builder.authorization("digest", authority.getBytes()); } client = builder.build(); client.getConnectionStateListenable().addListener(new CuratorConnectionStateListener(url)); client.start(); boolean connected = client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS); if (!connected) { throw new IllegalStateException("zookeeper not connected"); } } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } }

根据CuratorZookeeperClient方法可知,出现zookeeper not connected异常提示是发生在这一段代码当中——

if (!connected) { throw new IllegalStateException("zookeeper not connected"); }

connected表示连接状态,当它的值为false时,便会执行这段代码,那么,究竟是什么情况会导致它的值为false呢?

接下来,让我们打一个断点,一步一步解析这段代码。

首先,用作测试的dubbo和zookeeper配置如下——

dubbo: application: name: testervice registry: address: zookeeper://120.77.217.245 # timeout: 20000 protocol: name: dubbo port: 20880

解析来,开始debug,打断点,CuratorZookeeperClient方法参数url主要包含以下信息——


第一步、从url中获取超时时间timeout参数——

int timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_CONNECTION_TIMEOUT_MS);

这里的大概逻辑是,如果yaml配置registry注册zookeeper部分参数当中含有 timeout话,那么就返回配置当中定义的超时时间,如果yaml没有进行配置,那么,就用默认的超时时间,默认即常量DEFAULT_CONNECTION_TIMEOUT_MS,值是5 * 1000,也就是5秒,这个参数其实就是本篇文章的核心。

若自定义形式配置该参数,形式如下timeout: 20000——

dubbo: application: name: testervice registry: address: zookeeper://120.77.217.245 timeout: 20000

第二步、获取客户端过期时间——

int sessionExpireMs = url.getParameter(ZK_SESSION_EXPIRE_KEY, DEFAULT_SESSION_TIMEOUT_MS);

同理,无自定义配置话,则使用默认值DEFAULT_SESSION_TIMEOUT_MS = 60 * 1000,即6分钟;

第三步、创建一个设置过期时间为6分钟,连接超时为5秒,重试策略为每秒重试一次,连接服务端为url.getBackupAddress()(注:我这里得到的是120.77.217.245:9090,即配置的zookeeper连接url)的CuratorFramework客户端实例——

CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() .connectString(url.getBackupAddress()) .retryPolicy(new RetryNTimes(1, 1000)) .connectionTimeoutMs(timeout) .sessionTimeoutMs(sessionExpireMs); client = builder.build();

第四步、添加连接状态的监控,可以监控操作节点与连接情况——

client.getConnectionStateListenable().addListener(new CuratorConnectionStateListener(url));

第五步、开启客户端——

client.start();

最后一步,监控客户端连接情况,若能连接成功,则证明创建客户端成功,反之,失败。可见,若出现zookeeper not connected,问题就在于客户端连接过程是失败的,至于为何失败,原理就在client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS)代码里。

boolean connected = client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS); if (!connected) { throw new IllegalStateException("zookeeper not connected"); }

进入到 client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS)源码里,这里的maxWaitTime即前边的timeout,默认值是5秒,大概分析一下下边代码——

public synchronized boolean blockUntilConnected(int maxWaitTime, TimeUnit units) throws InterruptedException { //获取当前时间 long startTime = System.currentTimeMillis(); //这里是true boolean hasMaxWait = (units != null); //maxWaitTimeMs等于5000毫秒,即5秒 long maxWaitTimeMs = hasMaxWait ? TimeUnit.MILLISECONDS.convert(maxWaitTime, units) : 0; while ( !isConnected() ) { //hasMaxWait为true if ( hasMaxWait ) { //倒数5秒 long waitTime = maxWaitTimeMs - (System.currentTimeMillis() - startTime); //执行到这里,已经过去5秒话,就执行以下方法,返回isConnected()值 if ( waitTime <= 0 ) { return isConnected(); } //还没到5秒话,假如执行到这里还有3秒,那么就会执行Object.wait(long timeout)方法,即该线程阻塞3秒后再自动唤醒,接着继续执行 wait(waitTime); } else { wait(); } } return isConnected(); }

该方法的核心会等待maxWaitTime时间,时间一到,就会返回isConnected()值,这里其实很好理解,就是客户端发起连接后,这里用一个while循环来等待指定的超时时间,默认是5秒,若5秒过了,就返回isConnected()值,而这里的isConnected()就是验证是否连接成功了,

那么,这里就剩最后一个答案了,isConnected()是什么?

public synchronized boolean isConnected(){ return (currentConnectionState != null) && currentConnectionState.isConnected(); }

这里应该是判断客户端连接状态,即在client.start()方法里,会有一个状态,若创建连接成功,那么currentConnectionState.isConnected()就能得到true值,这里更像是一个观察模式,观察指定的连接超时时间内,是否连接成功。

根据debug,发现未连接成功时,值是null,得到的即为false,当我们把默认为5秒的连接超时设置为timeout: 20000,等待连接过程,发现连接成功了,返回currentConnectionState的值为RECONNECTED。

可见,之前出现zookeeper not connected异常问题,就是连接超时设置太短了!


currentConnectionState.isConnected()得到的是一个枚举值,RECONNECTED返回的是true——

CONNECTED { public boolean isConnected() { return true; } }, SUSPENDED { public boolean isConnected() { return false; } }, RECONNECTED { public boolean isConnected() { return true; } }, LOST { public boolean isConnected() { return false; } }, READ_ONLY { public boolean isConnected() { return true; } };

当返回true话,那么!connected就为false,就不会执行以下异常提示了——

if (!connected) { throw new IllegalStateException("zookeeper not connected"); }

根据上边分析,可见启动Dubbo项目注册Zookeeper时提示zookeeper not connected异常,是因为没有在配置里设置连接超时,而是使用了默认的5秒,导致5秒内没有成功连接,就出现连接异常而无法成功连接,当调长时间后,就正常连接成功了,同时也说明了,这次本地连接zookeeper集群的时间超过了五秒。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 14:15:23

Python新手学习

对于 Python 新手&#xff0c;我整理了一套零基础友好、可落地的学习路径 避坑指南&#xff0c;从入门准备到实战上手&#xff0c;一步步带你搞定&#xff1a;一、先搞定「基础准备」&#xff1a;选对工具 环境入门工具&#xff08;不用纠结复杂配置&#xff09;新手首选&…

作者头像 李华
网站建设 2026/7/7 11:11:42

Klavis AI国际化集成终极指南:构建多语言AI应用的完整解决方案

Klavis AI国际化集成终极指南&#xff1a;构建多语言AI应用的完整解决方案 【免费下载链接】klavis Klavis AI (YC X25): Open Source MCP Infra for Everyone 项目地址: https://gitcode.com/GitHub_Trending/kl/klavis 在全球化的数字时代&#xff0c;AI应用必须跨越语…

作者头像 李华
网站建设 2026/7/7 13:33:39

Qwen3-30B-A3B-Instruct-2507 实战手册:极速本地运行指南

挑战分析&#xff1a;大语言模型本地部署的行业痛点 【免费下载链接】Qwen3-30B-A3B-Instruct-2507 项目地址: https://ai.gitcode.com/hf_mirrors/Qwen/Qwen3-30B-A3B-Instruct-2507 当前企业部署大型语言模型面临诸多挑战&#xff0c;包括硬件成本高、部署复杂度大、…

作者头像 李华
网站建设 2026/7/7 7:15:20

Java Spring框架:从入门到进阶的十个核心维度

一、Spring框架概述&#xff1a;Java开发的"基础设施" Spring框架自2003年诞生以来&#xff0c;便彻底改变了Java企业级开发的格局。它以"轻量级"为核心特色&#xff0c;打破了早期EJB框架的臃肿与复杂&#xff0c;为开发者提供了一套全面的应用开发解决方…

作者头像 李华
网站建设 2026/7/7 9:08:50

Spring核心揭秘:IOC与DI的深度解析

在Spring框架的整个生态体系中&#xff0c;控制反转&#xff08;IOC&#xff09;与依赖注入&#xff08;DI&#xff09;是贯穿始终的核心思想&#xff0c;它们共同支撑起Spring“解耦”与“简化开发”的核心价值。很多开发者初学时容易将两者混淆&#xff0c;实际上IOC是设计思…

作者头像 李华
网站建设 2026/7/6 11:52:38

JSLint终极指南:全面提升JavaScript代码质量工具

JSLint终极指南&#xff1a;全面提升JavaScript代码质量工具 【免费下载链接】jslint JSLint, The JavaScript Code Quality and Coverage Tool 项目地址: https://gitcode.com/gh_mirrors/js/jslint 在JavaScript开发中&#xff0c;代码质量直接影响项目的可维护性和稳…

作者头像 李华