美文网首页
迁移Zookeeper时Dubbo是否会注册到新的ZK上

迁移Zookeeper时Dubbo是否会注册到新的ZK上

作者: 书唐瑞 | 来源:发表于2021-03-07 20:18 被阅读0次

    为了说明问题, 这里描述一下场景.

    应用配置的ZK地址是zk.infuq.com, 通过DNS解析的IP是192.168.0.1, 因此应用连接到了ZK1

    图片.png

    然后把DNS的映射关系改成如下图所示,让zk.infuq.com解析成ZK2的IP(192.168.0.2), 先关闭ZK1的服务(或者禁用2181端口的出入流量)过了1分钟再开启服务(目的就是让ZK1和应用断开连接),根据应用(Dubbo应用)的重连机制, 最后应用连接注册到ZK2上.

    图片.png

    然而, 这样操作之后, 应用真的可以连接到ZK2上吗?

    先说下答案, <font color="red">根据应用服务器配置的zookeeper版本不同,应用服务器可能还会连接到ZK1上,也可能会连接到ZK2上. </font>

    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.9</version>
    </dependency>
    

    如果使用的版本是3.4.9, 那么应用服务器会连接到ZK1上.

    Dubbo服务在启动的过程中,会连接ZK,其中会进入org.apache.zookeeper.client.StaticHostProvider#StaticHostProvider代码,实例化StaticHostProvider.

    public StaticHostProvider(Collection<InetSocketAddress> serverAddresses) throws UnknownHostException {
        for (InetSocketAddress address : serverAddresses) {
            // ia == null
            InetAddress ia = address.getAddress();
            // 解析IP
            InetAddress resolvedAddresses[] = InetAddress.getAllByName((ia!=null) ? ia.getHostAddress(): address.getHostName());
            for (InetAddress resolvedAddress : resolvedAddresses) {
                if (resolvedAddress.toString().startsWith("/") 
                    && resolvedAddress.getAddress() != null) {
                    this.serverAddresses.add(
                        new InetSocketAddress(InetAddress.getByAddress(
                            address.getHostName(),
                            resolvedAddress.getAddress()), 
                                              address.getPort()));
                } else {
                    this.serverAddresses.add(new InetSocketAddress(resolvedAddress.getHostAddress(), address.getPort()));
                }  
            }
        }
    
        if (this.serverAddresses.isEmpty()) {
            throw new IllegalArgumentException(
                "A HostProvider may not be empty!");
        }
        Collections.shuffle(this.serverAddresses);
    }
    

    它会根据域名解析IP, 拿到配置的zk.infuq.com域名,解析IP(192.168.0.1).

    解析出来的IP(192.168.0.1)最后封装成InetSocketAddress并放到serverAddresses集合中.

    图片.png

    也就是说,不管是首次连接ZK还是重连ZK,都是从serverAddresses集合中取出地址进行连接ZK,而不会再重新解析IP.

    如果是3.4.13版本

    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.13</version>
    </dependency>
    

    这个版本的逻辑是,如果需要连接ZK,都是调用下面的next方法获取地址. 而它每次都会解析IP,一旦DNS有变动,那么就会解析到新的IP地址.

    public InetSocketAddress next(long spinDelay) {
        ...
    
        InetSocketAddress curAddr = serverAddresses.get(currentIndex);
        try {
            // curHostString是域名,例如zk.infuq.com
            String curHostString = getHostString(curAddr);
            // 解析IP
            List<InetAddress> resolvedAddresses = new ArrayList<InetAddress>(Arrays.asList(this.resolver.getAllByName(curHostString)));
            if (resolvedAddresses.isEmpty()) {
                return curAddr;
            }
            Collections.shuffle(resolvedAddresses);
            // 返回地址
            return new InetSocketAddress(resolvedAddresses.get(0), curAddr.getPort());
        } catch (UnknownHostException e) {
            return curAddr;
        }
    }
    

    所以,最后结论如下图所示,根据不同的Zookeeper版本,应用会连接不同的ZK.

    图片.png

    相关文章

      网友评论

          本文标题:迁移Zookeeper时Dubbo是否会注册到新的ZK上

          本文链接:https://www.haomeiwen.com/subject/kubyqltx.html