赞
踩
我们以常见的微服务脚手架RuoYi-Cloud-Plus 为例
在微服务场景中,网关会从注册中心获取服务的列表,这些数据以键值对的形式存储在本地缓存中,key是服务的名称,value是服务的IP地址和端口号,通过服务名称查找IP地址和端口号,来明确要访问的服务,但是有些情况服务启动成功后发现有时候确无法调用成功。
没怎么了解网络的同学看这种类型的Ip会很疑惑,明明自己服务器/电脑根本不是这个开头的
调用后一般会出现这种错误
org.springframework.cloud.gateway.support.NotFoundException: 503 SERVICE_UNAVAILABLE "Unable to find instance for ruoyi-auth"
at org.springframework.cloud.gateway.support.NotFoundException.create(NotFoundException.java:45)
dubbo 调用最常见的一种网络错误
No provider available for the service xxxxxxx from registry xxxxxx:8848 on the consumer xxxxx using the dubbo version 3.1.11.
Please check if the providers have been started and registered.
其中针对这种类似问题dubbo专门开了个排查清单感兴趣的同学可以看看
在你检查了一遍后,你发现了nacos里面注册的IP不对并不是服务启动机器的IP。
那为什么会出现这种情况呢?
Spring Cloud服务注册到注册中心(如Nacos、Eureka等)时,服务实例IP地址的获取通常涉及到Spring Cloud框架下特定客户端库的源代码。对于不同的注册中心,具体的实现类会有所不同。这里以Spring Cloud Alibaba Nacos Discovery为例,简述相关源码位置:
在**NacosDiscoveryProperties#init()**方法中进行了服务IP的初始化行为
在这里会先判断两个配置
1:spring.cloud.nacos.discovery.ip: 指定服务实例在注册到 Nacos 时使用的 IP 地址
2:spring.cloud.nacos.discovery.networkInterface: 指定服务实例用来检测 IP 地址的网络接口
如果没有设置IP,且没有设置网卡的情况下会调用InetUtils#findFirstNonLoopbackHostInfo()
核心代码如下
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(); } //判断是否已经获取到了IP地址 else if (result != null) { continue; } //是否忽略网卡 //如果配置了 spring.cloud.inetutils.ignored-interfaces[0]=eth0 if (!ignoreInterface(ifc.getDisplayName())) { for (Enumeration<InetAddress> addrs = ifc .getInetAddresses(); addrs.hasMoreElements();) { //开始遍历网卡的接口 InetAddress address = addrs.nextElement(); if (address instanceof Inet4Address && !address.isLoopbackAddress() && isPreferredAddress(address)) { //address.isLoopbackAddress() 是否为回环地址 //前缀匹配 针对spring.cloud.inetutils.preferred-networks配置项 //专门指定某个特定的ip前缀进行IP获取类似于左模糊 比如10.0.0;那么它只会找到这个IP段的进行匹配(前缀匹配或全匹配) log.trace("Found non-loopback interface: " + ifc.getDisplayName()); result = address; } } } } } }
可以看到是默认遍历所有网卡接口依次获取,如果已拿到就会跳过后面的获取
如果你其他网卡的顺序在你本机IP那张网卡之前,那么获取的结果就有可能混乱。
导致服务实例可能注册到一个内网不可达或者非公网IP上,从而影响服务间的正常通信。
再来看一下Dubbo的host获取规则
在 Dubbo 中, Provider 启动时主要做两个事情
一是启动 server
二是向注册中心注册服务。启动 server 时需要绑定 socket
向注册中心注册服务时也需要发送 socket 唯一标识服务地址。
查看代码发现,在 org.apache.dubbo.config.ServiceConfig#findConfigedHosts() 中
通过 InetAddress.getLocalHost().getHostAddress() 获取默认 host。
先看一下**ServiceConfig#findConfigedHosts()**做了一件什么事情
1:先从环境变量获取DUBBO_IP_TO_BIND。
2:如果为空则通过 NetUtils.getLocalHost() 获取默认 host。
3:然后通过**NetUtils.getValidNetworkInterfaces()**拿到系统所有网卡列表并过滤出可用的。
4:接着遍历获取第一个可达的网络接口,如果仍找不到,则返回列表中的第一个网络接口。如果没有任何网络接口可用,则返回null。
5:如果为空则继续从环境变量中获取DUBBO_IP_TO_REGISTRY并返回。
spring:
cloud:
nacos:
discovery:
ip: xxx.xxx.xxx.xxx
这样nacos客户端就会使用你指定好的IP进行服务注册
如果你希望服务实例一直使用某个特定的网络段,比如你的内网10.1.xxxx.xxxxx那么可以使用这个配置,配置后spring cloud会优先匹配。这样就能保证你服务实例所在宿主机的ip可以正常注册。
spring:
cloud:
inetutils:
preferred-networks:
- 10.1
当服务实例启动时,Nacos 客户端会根据这个配置去查询指定网络接口上的 IP 地址,并使用查询到的地址进行服务注册。如果你的服务器有多块网卡,或者希望服务使用特定网卡上的 IP 地址注册,可以通过设置这个属性来控制。配置的值应该是网络接口的名称,如 eth0 或 en0。
spring:
cloud:
nacos:
discovery:
network-interface: xxxx
有些部署场景需要动态指定服务注册的地址,如 docker bridge 网络模式下要指定注册宿主机 ip 以实现外网通信。dubbo 提供了两对启动阶段的系统属性,用于设置对外通信的ip、port地址。
环境变量如下
DUBBO_IP_TO_REGISTRY:注册到注册中心的 ip 地址
DUBBO_PORT_TO_REGISTRY:注册到注册中心的 port 端口
DUBBO_IP_TO_BIND:监听 ip 地址
DUBBO_PORT_TO_BIND:监听 port 端口
示例docker脚本
docker run --name my-server -d -p 80:8080 -p 28880:28880 --restart=always \
# 指定dubbo注册到注册中心的IP地址
-e DUBBO_IP_TO_REGISTRY=192.168.2.2 \
-e DUBBO_PORT_TO_REGISTRY=20880 \
test-image1111
这里的优先级高于dubbo.protocol或dubbo.provider的host配置
dubbo:
protocol:
host: xxx.xxx.xxx.xxx
1:如果您的开发环境中存在多块网卡,如因安装了虚拟机软件(如VMware)、使用了VPN或其他网络工具,可能会出现多个网络接口。
Nacos在默认情况下可能会选择到非预期的网卡IP进行注册,比如虚拟机的网络适配器(如VMware Network Adapter VMnet1)或VPN分配的IP地址。
这会导致注册到Nacos的服务IP与您期望的实际服务运行IP(如本机IP 127.0.0.1或物理网卡的IP)不一致,进而影响服务发现和路由。
2:可以通过手动指定IP,网卡或网络段来依次固定。
3: 通过dubbo.protocol或dubbo.provider的host属性对host进行配置,支持IP地址和域名.但此时注册到注册中心的IP地址和监听IP地址是同一个值
4: dubbo可以通过环境变量分别设置注册到注册中心的IP地址和监听IP地址,其优先级高于dubbo.protocol或dubbo.provider的host配置
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。