1. 程式人生 > >[SpringCloud-Eureka] zookeeper和Eureka使用IP註冊

[SpringCloud-Eureka] zookeeper和Eureka使用IP註冊

一.註冊IP而不是服務名稱

1.1 問題 : 在使用Eureka和Zookeeper作為註冊中心的時候,均是預設註冊主機名稱,但是很多時候主機名稱解析會有問題,通過配置使用IP註冊:

Eureka:
 eureka.instance.prefer-ip-address = true
Zookeeper:
zookeeper中的配置很隱蔽,查了很久,配置形式如下:
spring.cloud.zookeeper.discovery.instance-host=${spring.cloud.client.ipAddress}
這裡右邊可以寫成IP,但是寫成IP不好,比如使用配置中心多例項共享一份配置就有問題,因此寫成這樣,會
動態獲取例項執行的主機的ip。配置後,就可以將IP註冊到zookeeper,其他服務使用Feign呼叫就不會有問題了。

二.Eureka註冊IP解讀

2.1 配置註冊IP

通過eureka.instance.prefer-ip-address = true配置,將微服務的IP註冊到Eureka,而不是主機名稱
程式碼解析如下:
在org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean類的getHostName方法中:
        @Override
	public 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;
	}
	這裡可以看到最後返回時通過preferIpAddress配置項來決定返回的是IP還是主機名稱,如下所示,預設是false,
	也就是預設註冊的是this.hostname主機名稱:
	/**
	 * Flag to say that, when guessing a hostname, the IP address of the server should be
	 * used in prference to the hostname reported by the OS.
	 */
	private boolean preferIpAddress = false;
  • 總言之:eureka.instance.prefer-ip-address = true通過該配置項可以往Eureka註冊IP而不是主機名(預設是主機名稱);

2.2 配置自定義IP

配置項spring.cloud.client.ipAddress可指定一個IP,如果指定了IP同時開啟eureka.instance.prefer-ip-address=true
的話,那麼會註冊哪一個資訊呢?我們跟進if (refresh && !this.hostInfo.override) 這個判斷條件,refresh如果為false則
直接走下面的return返回不會再去執行兩個get方法(可以理解為不去重新獲取,即不refresh重新整理),那麼條件取決於
HostInfo的override屬性,跟進:根據setIpAddress方法我們看到,當設定了eureka.instance.ipAddress時,override
會設定為true,,那麼在執行上面的邏輯的時候,就不會再執行hostInfo的getIpAddress和getHostname方法了,因此
就會直接返回this.ipAddress,而這個ipAddress就是spring.cloud.client.ipAddress指定的。
	public void setIpAddress(String ipAddress) {
		this.ipAddress = ipAddress;
		this.hostInfo.override = true;
	}
  • 總言之:配置了eureka.instance.prefer-ip-address = true和spring.cloud.client.ipAddress的情況下,會註冊spring.cloud.client.ipAddress指定的IP,而不會通過findFirstNonLoopbackHostInfo方法去尋找本機的非迴環地址;

3.findFirstNonLoopbackAddress方法

下面是簡單改造過的findFirstNonLoopbackAddress方法,通過該方法可以獲取本機的非迴環IP地址

public 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

                        for (Enumeration<InetAddress> addrs = ifc
                                .getInetAddresses(); addrs.hasMoreElements();) {
                            InetAddress address = addrs.nextElement();
                            if (address instanceof Inet4Address
                                    && !address.isLoopbackAddress()
                                   ) {
                                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;
    }