Spring Gateway集成 Nacos注册中心不能够发现服务的问题解决
一、问题描述我们现在是在用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中Eur
一、问题描述
我们现在是在用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的怪问题都让我给碰上了!
更多推荐
所有评论(0)