Sentinel VirtualBox(vbox)虚拟网卡和物理网卡同时存在时,sentinel获取ip出错,

ny6fqffe  于 2022-10-19  发布在  其他
关注(0)|答案(5)|浏览(255)

VirtualBox(vbox)虚拟网卡和物理网卡同时存在时,sentinel获取ip出错,问题细节描述如下:

1.在A主机上运行sentinel;
2.在B主机(物理机)上运行需要被监测流量的应用 app1;
3.在B主机上同时存在物理网卡和虚拟网卡(VirtualBox Host-Only Network),并运行 app1;
4.在A主机sentinel的控制面板(控制台)上获取的机器列表中: 取得的是app1所在主机B的虚拟网卡 VirtualBox Host-Only Network的地址,从而造成监测失败;
5.错误在于sentinel不应该取得B主机虚拟网卡ip, 而应该取得物理网卡ip,因为app1运行在物理机中。

【临时解决方法】:
把虚拟网卡 VirtualBox Host-Only Network 禁用即可,希望大神能从代码层面解决这个问题。据测试VMware的虚拟网卡不会出现类似的问题。

rlcwz9us

rlcwz9us1#

Would you like to submit a PR to improve relevant logic?

muk1a3rh

muk1a3rh2#

确实是这样的,我的服务A运行在docker内,服务注册到nacos上面,nacos显示的就是物理网卡的ip,同时注册到sentinel控制台,sentinel就显示的是虚拟ip。
sentinel获取ip的逻辑在com.alibaba.csp.sentinel.util.HostNameUtil.java里面:

private static void resolveHost() throws Exception {
        InetAddress addr = InetAddress.getLocalHost();
        hostName = addr.getHostName();
        ip = addr.getHostAddress();
        if (addr.isLoopbackAddress()) {
            // find the first IPv4 Address that not loopback
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface in = interfaces.nextElement();
                Enumeration<InetAddress> addrs = in.getInetAddresses();
                while (addrs.hasMoreElements()) {
                    InetAddress address = addrs.nextElement();
                    if (!address.isLoopbackAddress() && address instanceof Inet4Address) {
                        ip = address.getHostAddress();
                    }
                }
            }
        }
    }

nacos获取ip的的逻辑在org.springframework.cloud.commons.util.InetUtils.java里面:

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()) {
					this.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()
									&& isPreferredAddress(address)) {
								this.log.trace("Found non-loopback interface: "
										+ ifc.getDisplayName());
								result = address;
							}
						}
					}
					// @formatter:on
				}
			}
		}
		catch (IOException ex) {
			this.log.error("Cannot get first non-loopback address", ex);
		}

		if (result != null) {
			return result;
		}

		try {
			return InetAddress.getLocalHost();
		}
		catch (UnknownHostException e) {
			this.log.warn("Unable to retrieve localhost");
		}

		return null;
	}

sentinel能不能也参照nacos的获取ip逻辑优化下?

pepwfjgg

pepwfjgg3#

@ifrozenice Would you like to submit a PR to improve it?

rqmkfv5c

rqmkfv5c4#

我想从代码层面解决这个错误,但是目前以我的能力还还办不到。

qcuzuvrc

qcuzuvrc5#

越来越多的关于获取ip的问题。其实这里有一个成本较高但可用的fix可以尝试,那就是做一次当前节点到dashboard汇报节点的路由查找。路由查找成功后(网络能连通的情况下),本端ip即为正确ip。

路由查找的方式,除了获取路由表直接查找,还有一种比较近似的方法,就是尝试创建一下连接,从而拿到本端ip。

获取默认路由的方法(gateway)(直接使用数据报测试1.1.1.1的连通性):

try(DatagramSocket s=new DatagramSocket())
{
    s.connect(InetAddress.getByAddress(new byte[]{1,1,1,1}), 0);
    return NetworkInterface.getByInetAddress(s.getLocalAddress()).getHardwareAddress();
}

更准确的,可以把目标ip更换为dashboard地址。

相关问题