Spring Boot 连接 ZooKeeper 注册中心发生异常的排查经历

XuNeely 2020-04-22

排错

使用 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 属性:

Spring Boot 连接 ZooKeeper 注册中心发生异常的排查经历

更改 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

启动项目 ... 启动成功!

Spring Boot 连接 ZooKeeper 注册中心发生异常的排查经历

到 dubbo-admin 看一下:

Spring Boot 连接 ZooKeeper 注册中心发生异常的排查经历

已注册到 ZooKeeper 。

IDEA 下载源码的方式

IDEA 下载源码的方式非常简单,点进源码的时候点击右上角的 Downoad Sources 即可:

Spring Boot 连接 ZooKeeper 注册中心发生异常的排查经历

相关推荐