dubbo注冊服務IP解析異常及IP解析源碼分析


在使用dubbo注冊服務時會遇到IP解析錯誤導致無法正常訪問.
比如: 本機設置的IP為172.16.11.111, 但實際解析出來的是180.20.174.11
這樣就導致這個Service永遠也無法被訪問到, 而調用方一直報錯.

當然若發現服務無法訪問, 最好先通過dubbo-admin后台排查下注冊的服務是否正常.

IP解析異常時的解決方法:

  • 綁定hostname+ip
    1. 先查看機器的hostname
    2. 修改hosts文件, 增加hostname 172.16.11.111
  • 配置nameserver
    排查機器上配置的nameserver是否有問題, 若存在無用的nameserver則直接刪掉
  • 在dubbo的配置文件中寫死host
    <dubbo:protocol host="172.16.11.111"/>
    或者在每個provider中綁定host
    <dubbo:provider host="172.16.11.111">

最好不要用第三種方式, 限制太多. 而且如果這樣做了就不支持集群了.
dubbo的官網也不建議使用這種方式. 請慎用.

dubbo獲取IP源碼分析


    /**
     * 判斷host是否為不可用的本地Host
     */
    public static boolean isInvalidLocalHost(String host) {
        return host == null 
                    || host.length() == 0
                    || host.equalsIgnoreCase("localhost")
                    || host.equals("0.0.0.0")
                    || (LOCAL_IP_PATTERN.matcher(host).matches());
    }

    /**
     * 獲取本地Host.
     * 若address == null ? "127.0.0.1" : InetAddress.getHostAddress();
     */
    public static String getLocalHost(){
        InetAddress address = getLocalAddress();
        return address == null ? LOCALHOST : address.getHostAddress();
    }

    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        ...
        ...
        //1. 先從ProtocolConfig中取host. 若沒有配置則為null
        String host = protocolConfig.getHost();

        //2. 再從ProviderConfig中取host. 若沒有配置則為null
        if (provider != null && (host == null || host.length() == 0)) {
            host = provider.getHost();
        }

        boolean anyhost = false;

        //3. 若取出的是本地host, 則繼續取host
        if (NetUtils.isInvalidLocalHost(host)) {
            anyhost = true;
            try {
                //4. 通過InetAddress的方式獲取Host
                //默認讀取本機hosts中hostname對應的IP
                //如: 你在hosts中配置了 leo 172.16.11.111
                //則讀取的IP就是172.16.11.111
                host = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                logger.warn(e.getMessage(), e);
            }
            if (NetUtils.isInvalidLocalHost(host)) {
                if (registryURLs != null && registryURLs.size() > 0) {
                    for (URL registryURL : registryURLs) {
                        try {
                            Socket socket = new Socket();
                            try {
                                //5. 通過Socket的方式獲取Host
                                //一般解析到這里, 都會獲取到正確的本地IP, 除非你有多網卡, 或者有VPN, 導致無法正常解析.
                                SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
                                socket.connect(addr, 1000);
                                host = socket.getLocalAddress().getHostAddress();
                                break;
                            } finally {
                                try {
                                    socket.close();
                                } catch (Throwable e) {}
                            }
                        } catch (Exception e) {
                            logger.warn(e.getMessage(), e);
                        }
                    }
                }

                //6. 遍歷本地網卡, 返回第一個合理的Host
                //最后一個大招. 當上述都解析不到時, 則會遍歷本地網卡.
                //逐個獲取IP, 直到有一個合理的IP為止.
                if (NetUtils.isInvalidLocalHost(host)) {
                    host = NetUtils.getLocalHost();
                }
            }
        }
        ...
    }

    /**
     * 遍歷本地網卡,返回第一個合理的IP。
     * @return 本地網卡IP
     */
    public static InetAddress getLocalAddress() {
        if (LOCAL_ADDRESS != null)
            return LOCAL_ADDRESS;
        InetAddress localAddress = getLocalAddress0();
        LOCAL_ADDRESS = localAddress;
        return localAddress;
    }

    /**
     * 遍歷本地網卡,返回第一個合理的IP。
     * @return 本地網卡IP
     */
    private static InetAddress getLocalAddress0() {
        InetAddress localAddress = null;
        try {
            localAddress = InetAddress.getLocalHost();
            if (isValidAddress(localAddress)) {
                return localAddress;
            }
        } catch (Throwable e) {
            logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
        }
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            if (interfaces != null) {
                while (interfaces.hasMoreElements()) {
                    try {
                        NetworkInterface network = interfaces.nextElement();
                        Enumeration<InetAddress> addresses = network.getInetAddresses();
                        if (addresses != null) {
                            while (addresses.hasMoreElements()) {
                                try {
                                    InetAddress address = addresses.nextElement();
                                    if (isValidAddress(address)) {
                                        return address;
                                    }
                                } catch (Throwable e) {
                                    logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
                                }
                            }
                        }
                    } catch (Throwable e) {
                        logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
                    }
                }
            }
        } catch (Throwable e) {
            logger.warn("Failed to retriving ip address, " + e.getMessage(), e);
        }
        logger.error("Could not get local host ip address, will use 127.0.0.1 instead.");
        return localAddress;
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM