irpas技术客

Spring Gateway集成 Nacos注册中心不能够发现服务的问题解决_冯立彬_nacos发现不了服务

网络 3721

一、问题描述

我们现在是在用Nacos替换Eureka,原来Eureka和Spring gateway运行正常,可以通过Spring gateway调用注册到Eureka中的服务。

当前Spring cloud的版本是Hoxton.SR8,Nacos discovery的版本为0.9.0.RELEASE,使用的Nacos版本为2.0.3。

Nacos替换Eureka改动的地方如下:

1、去掉POM中Eureka的引入;

2、去掉主类中引入的@EnableEurekaClient注解;

3、引入Nacos依赖:

<dependency> ??<groupId>org.springframework.cloud</groupId> ??<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> ??<version>0.9.0.RELEASE</version> ??<exclusions> ????<exclusion> ????????<groupId>com.alibaba.nacos</groupId> ????????<artifactId>nacos-client</artifactId> ????</exclusion> ????<exclusion> ???? <groupId>org.springframework.cloud</groupId> ???? <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> ????</exclusion> ??</exclusions> </dependency> <dependency> ??<groupId>com.alibaba.nacos</groupId> ??<artifactId>nacos-client</artifactId> ??<version>2.0.3</version> </dependency>

4、引入spring-cloud-loadbalancer:

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> </dependency>

5、spring-cloud-starter-openfeign中exclude掉ribbon的依赖:

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <exclusions> <exclusion> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-ribbon</artifactId> </exclusion> </exclusions> </dependency>

6、application.yml中禁用nacos的ribbon:

ribbon: ??nacos: ????enabled: false

现在的现象:

Spring gateway启动不报错;gateway也可以正常注册到Nacos;通过打断点到NacosDiscoveryClientAutoConfiguration,NacosDiscoveryClient会被初使化,但是调用时不会调用NacosDiscoveryClient.getInstances(String)获取被调用应用的Provider,会报类似下面的接口404错误:

{"msg":"/user-service/user/getByToken","result":404,"data":null}

其中user-service为注册到Nacos上面的服务名称,但是就是不能够被调用到。

Spring gateway的注册中心切换为Eureka,再次调用服务时,Eureka的CompositeDiscoveryClient.getInstances(String)方法就会被调用。 二、问题分析

前面走了一些弯路,也花了一些时间,最后想到的是与Eureka注册中心进行对比调试分析,下面例出关键的分析步骤。

Debug断点打到DiscoveryClientRouteDefinitionLocator两个构造函数上,只有参数是ReactiveDiscoveryClient的构造函数被加载:

继续跟踪到ReactiveCompositeDiscoveryClient.getServices()方法:

发现数组变量discoveryClients包含了两个实现,如下图所示:

其中有一个是EurekaReactiveDiscoveryClient,那在使用Nacos时就应该包含一个针对Nacos实现的ReactiveDiscoveryClient,于是切换为Nacos分支调试。

但是调试发现数组变量discoveryClients并没有包含针对Nacos实现的ReactiveDiscoveryClient:

于是参考EurekaReactiveDiscoveryClient以及NacosDiscoveryClient,立即就写了NacosReactiveDiscoveryClient:

import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; import org.springframework.cloud.alibaba.nacos.NacosServiceInstance; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ListView; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; /** * * @author fenglibin * */ @Slf4j public class NacosReactiveDiscoveryClient implements ReactiveDiscoveryClient { public static final String DESCRIPTION = "Spring Cloud Nacos Reactive Discovery Client"; private NacosDiscoveryProperties discoveryProperties; public NacosReactiveDiscoveryClient(NacosDiscoveryProperties discoveryProperties) { this.discoveryProperties = discoveryProperties; } @Override public String description() { return DESCRIPTION; } @Override public Flux<ServiceInstance> getInstances(String serviceId) { try { List<Instance> instances = discoveryProperties.namingServiceInstance().selectInstances(serviceId, true); return Flux.fromStream(hostToServiceInstanceList(instances, serviceId).stream()); } catch (Exception e) { throw new RuntimeException("Can not get hosts from nacos server. serviceId: " + serviceId, e); } } @Override public Flux<String> getServices() { try { ListView<String> services = discoveryProperties.namingServiceInstance().getServicesOfServer(1, Integer.MAX_VALUE); return Flux.fromStream(services.getData().parallelStream()); } catch (Exception e) { log.error("get service name from nacos server fail,", e); return Flux.fromStream(Collections.<String>emptyList().stream()); } } private static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) { NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); nacosServiceInstance.setHost(instance.getIp()); nacosServiceInstance.setPort(instance.getPort()); nacosServiceInstance.setServiceId(serviceId); Map<String, String> metadata = new HashMap<>(); metadata.put("nacos.instanceId", instance.getInstanceId()); metadata.put("nacos.weight", instance.getWeight() + ""); metadata.put("nacos.healthy", instance.isHealthy() + ""); metadata.put("nacos.cluster", instance.getClusterName() + ""); metadata.putAll(instance.getMetadata()); nacosServiceInstance.setMetadata(metadata); if (metadata.containsKey("secure")) { boolean secure = Boolean.parseBoolean(metadata.get("secure")); nacosServiceInstance.setSecure(secure); } return nacosServiceInstance; } private static List<ServiceInstance> hostToServiceInstanceList(List<Instance> instances, String serviceId) { List<ServiceInstance> result = new ArrayList<>(instances.size()); for (Instance instance : instances) { result.add(hostToServiceInstance(instance, serviceId)); } return result; } }

或者集成如下starter:

<dependency> <groupId>com.eeeffff</groupId> <artifactId>nacos-reactive-discovery-client</artifactId> <version>1.0.0</version> </dependency>

并在启动时创建Bean:

再次启动调试就可以看到数组变量discoveryClients中有NacosReactiveDiscoveryClient了:

?再次通过网关请求服务,就可以正常调用成功了。

?感觉Nacos的怪问题都让我给碰上了!


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #nacos发现不了服务 #当前Spring