1. 程式人生 > >Eureka服務註冊過程詳解之IpAddress

Eureka服務註冊過程詳解之IpAddress

閱讀本文你將瞭解

  • 微服務註冊到Eureka Server上的粗粒度過程
  • eureka.instance.prefer-ip-address = true 時,發生的一些事
  • 深度理解eureka.instance.ip-address 和eureka.instance.prefer-ip-address = true 。
  • 雜談

注:本篇較長、枯燥、燒腦,並且涉及的範圍相對廣,建議選擇一個舒服的姿勢閱讀。

分析,eureka.instance.prefer-ip-address

  • 本節解釋為什麼配置eureka.instance.prefer-ip-address = true時,註冊到Eureka Server上的是IP,以及是什麼IP

老套路,定位問題從配置開始。

(1) 我們通過eureka.instance.prefer-ip-address 配置項,可以找到原始碼

1org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.preferIpAddress

(2) preferIpAddress被哪裡呼叫,可以找到

1org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.getHostName(boolean)

程式碼如下:

12345678@Overridepublic String getHostName
(boolean refresh)
{ if (refresh && !this.hostInfo.override) { this.ipAddress = this.hostInfo.getIpAddress(); this.hostname = this.hostInfo.getHostname(); } return this.preferIpAddress ? this.ipAddress : this.hostname;}

從這裡我們可以知道,為什麼配置eureka.instance.prefer-ip-address = true 就可以將IP註冊到Eureka Server上,而如果不配置就是機器的主機名。

我們看到以上程式碼有個hostInfo,這是在哪裡例項化的呢?

(3) hostInfo在

1org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean

的構造方法中例項化!我們來閱讀該類的構造方法:

123456public EurekaInstanceConfigBean(InetUtils inetUtils) { this.inetUtils = inetUtils; this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo(); this.ipAddress = this.hostInfo.getIpAddress(); this.hostname = this.hostInfo.getHostname();}

從中 可以看到,hostInfo是呼叫了

1this.inetUtils.findFirstNonLoopbackHostInfo();

從中可以看到,原來hostInfo是呼叫了

1org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackHostInfo()

(4) 閱讀

1org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackHostInfo()

可以看到以下程式碼:

12345678910public HostInfo findFirstNonLoopbackHostInfo() { InetAddress address = findFirstNonLoopbackAddress(); if (address != null) { return convertAddress(address); } HostInfo hostInfo = new HostInfo(); hostInfo.setHostname(this.properties.getDefaultHostname()); hostInfo.setIpAddress(this.properties.getDefaultIpAddress()); return hostInfo;}

我們再看一下該類的

1org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackAddress()

方法:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051public InetAddress findFirstNonLoopbackAddress() { InetAddress result = null; try { int lowest = Integer.MAX_VALUE; for (Enumeration<NetworkInterface> nics = NetworkInterface .getNetworkInterfaces(); nics.hasMoreElements();) { NetworkInterface ifc = nics.nextElement(); if (ifc.isUp()) { log.trace("Testing interface: " + ifc.getDisplayName()); if (ifc.getIndex() < lowest || result == null) { lowest = ifc.getIndex(); } else if (result != null) { continue; } // @formatter:off if (!ignoreInterface(ifc.getDisplayName())) { for (Enumeration<InetAddress> addrs = ifc .getInetAddresses(); addrs.hasMoreElements();) { InetAddress address = addrs.nextElement(); if (address instanceof Inet4Address && !address.isLoopbackAddress() && !ignoreAddress(address)) { log.trace("Found non-loopback interface: " + ifc.getDisplayName()); result = address; } } } // @formatter:on } } } catch (IOException ex) { log.error("Cannot get first non-loopback address", ex); } if (result != null) { return result; } try { return InetAddress.getLocalHost(); } catch (UnknownHostException e) { log.warn("Unable to retrieve localhost"); } return null;}

至此,終於找到了獲得IP的詳細方法,原來只需要配置eureka.instance.prefer-ip-address = true,Spring就會自動為我們獲取第一個非迴環IP地址(這只是簡單的說法,事實上這段程式碼有些容錯的處理)。程式碼雖然長,但是很清晰。不做贅述。

eureka.instance.ip-address和eureka.instance.prefer-ip-address = true同時設定,會用自動獲取的ip還是手動設定的?

上文是討論設定eureka.instance.prefer-ip-address = true ,但沒有指定eureka.instance.ip-address 的情況。那麼如果兩者都被指定了,Spring會怎麼處理呢?是使用eureka.instance.ip-address手動設定的IP,還是用上面自動獲取的IP呢?

答案是聽eureka.instance.ip-address的。

原因是:在

1org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.setIpAddress(String)

中:

1234public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; this.hostInfo.override = true;}

這邊設定了this.hostInfo.override,因此會導致getHostName方法不會進if語句,直接返回this.ipAddress。

12345678@Overridepublic String getHostName(boolean refresh) { if (refresh && !this.hostInfo.override) { this.ipAddress = this.hostInfo.getIpAddress(); this.hostname = this.hostInfo.getHostname(); } return this.preferIpAddress ? this.ipAddress : this.hostname;}

B.T.W

回到上文的

1org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackAddress()

方法,上面有很多ignoreXXX的程式碼。那麼,如何配置想要忽略的網絡卡或者IP地址呢?

答案非常簡單,詳見Spring Cloud官方文件:

當然了,這些配置的本意並不是用來註冊到Eureka上的,而是用作其他用途,只不過如果沒有設定eureka.instance.ip-address時,這個IP就是註冊到Eureka Server上的IP。

我們可以在應用的/env端點看到Spring為我們挑選的IP:

1234springCloudClientHostInfo: { spring.cloud.client.hostname: "itmuch", spring.cloud.client.ipAddress: "192.168.0.59"},