Spring Boot 连接 ZooKeeper 注册中心发生异常的排查经历
排错
使用 Spring Boot 整合 Dubbo + ZooKeeper 的时候,启动 Provider 时发生异常:
Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug‘ enabled. 2020-04-22 10:29:47.822 ERROR 11072 --- [ main] o.s.boot.SpringApplication : Application run failed java.lang.IllegalStateException: zookeeper not connected at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:83) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter.createZookeeperClient(CuratorZookeeperTransporter.java:26) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperTransporter.connect(AbstractZookeeperTransporter.java:70) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter$Adaptive.connect(ZookeeperTransporter$Adaptive.java) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration.<init>(ZookeeperDynamicConfiguration.java:70) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory.createDynamicConfiguration(ZookeeperDynamicConfigurationFactory.java:37) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory.lambda$getDynamicConfiguration$0(AbstractDynamicConfigurationFactory.java:39) ~[dubbo-2.7.6.jar:2.7.6] at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_251] at org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory.getDynamicConfiguration(AbstractDynamicConfigurationFactory.java:39) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.common.config.configcenter.DynamicConfiguration.getDynamicConfiguration(DynamicConfiguration.java:223) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.bootstrap.DubboBootstrap.prepareEnvironment(DubboBootstrap.java:857) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.bootstrap.DubboBootstrap.startConfigCenter(DubboBootstrap.java:603) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.bootstrap.DubboBootstrap.useRegistryAsConfigCenterIfNecessary(DubboBootstrap.java:671) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.bootstrap.DubboBootstrap.initialize(DubboBootstrap.java:509) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:740) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener.onContextRefreshedEvent(DubboBootstrapApplicationListener.java:59) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener.onApplicationContextEvent(DubboBootstrapApplicationListener.java:52) ~[dubbo-2.7.6.jar:2.7.6] at org.apache.dubbo.config.spring.context.OneTimeExecutionApplicationContextEventListener.onApplicationEvent(OneTimeExecutionApplicationContextEventListener.java:40) ~[dubbo-2.7.6.jar:2.7.6] at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE] at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE] at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE] at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE] at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162) ~[spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1204) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE] at com.touyel.lesson.dubbo.provider.DubboProviderSampleApplication.main(DubboProviderSampleApplication.java:10) [classes/:na] Caused by: java.lang.IllegalStateException: zookeeper not connected at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:80) ~[dubbo-2.7.6.jar:2.7.6] ... 32 common frames omitted
我是使用 docker 搭建的 ZooKeeper 注册中心:
version: ‘3.1‘ services: zookeeper: image: zookeeper container_name: zookeeper restart: always ports: - 2181:2181 dubbo-admin: image: apache/dubbo-admin container_name: dubbo-admin depends_on: - zookeeper ports: - 9050:8080 environment: - admin.registry.address=zookeeper://zookeeper:2181 - admin.config-center=zookeeper://zookeeper:2181 - admin.metadata-report.address=zookeeper://zookeeper:2181
ZooKeeper 是没有什么问题的,那就从代码中寻找问题了。
先看一下抛异常的源码:
java.lang.IllegalStateException: zookeeper not connected at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:83) ~[dubbo-2.7.6.jar:2.7.6]
[没有下载源码的,最好把源码下载好(下载方式见底部)。](## IDEA 下载源码的方式)
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); } }
可以发现两行关键代码:
int timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_CONNECTION_TIMEOUT_MS); boolean connected = client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS);
这里的 TIMEOUT_KEY
就是一个 key:String TIMEOUT_KEY = "timeout";
根据这个 timeout
,推断可能是 timeout
超时时间设置太短,没有时间连接上 ZooKeeper 。
点进去看一下 this.DEFAULT_CONNECTION_TIMEOUT_MS
默认设置的时间:
protected int DEFAULT_CONNECTION_TIMEOUT_MS = 5 * 1000;
根据 client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS);
得出这里的单位为毫秒。那么这里的 timeout
默认设置为 5
秒。
官方文档 schema 配置参考手册/dubbo:registry
到 application.properties
中看一下 timeout 属性:
更改 timeout 的默认值为 10秒(仍然连接不上的可以增大时间):
dubbo.registry.timeout=10000
application.properties
server.port=9001 dubbo.application.name=provider-sample dubbo.registry.protocol=zookeeper dubbo.registry.address=zookeeper://192.168.59.130:2181 dubbo.protocol.name=dubbo dubbo.protocol.port=-1 dubbo.registry.timeout=10000 dubbo.scan.base-packages=com.touyel.lesson.dubbo.provider.service
启动项目 ... 启动成功!
到 dubbo-admin 看一下:
已注册到 ZooKeeper 。
IDEA 下载源码的方式
IDEA 下载源码的方式非常简单,点进源码的时候点击右上角的 Downoad Sources
即可: