Skip to content
铭师堂的云原生升级实践Know more

Nacos 客户端寻址

在使用Nacos时, Nacos客户端需要配置Nacos服务器的地址,以确保客户端能连接到Nacos服务器,从而实现服务发现和注册等功能。

本文档将介绍Nacos客户端的各种寻址逻辑,以及多种不同的寻址方式的优先级;对于部分支持拓展寻址的编程语言的客户端,本文档还会介绍如何实现自定义的寻址逻辑。

1. 客户端寻址基本逻辑

Nacos的所有客户端在寻址Nacos服务端时,虽然具体的实现有所差异,但基本都遵循如下逻辑:

寻址基本逻辑

  1. 首先,Nacos客户端会根据初始化时,接受来自应用的配置,如Properties等信息;
  2. 在Nacos客户端初始化过程中,会创建一个ServerListManager(服务列表管理器),用于管理服务端的地址列表;
  3. 根据传入的Properties配置信息,ServerListManager会选择一个对应的ServerListProvider(服务列表提供者)来实际获取服务端地址列表,默认情况下,Nacos客户端会提供基于server-addr配置PropertiesServerListProvider,和Endpoint 地址服务器EndpointServerListProvider
  4. ServerListManager完成ServerListProvider的选取、初始化以及从其中获取到服务端地址列表后,Nacos客户端才会创建用于通信的GrpcClient,并使用ServerListManager管理的服务端地址列表来创建连接,并请求对应的Nacos Server。

不同的ServerListProvider会导致客户端在寻找服务端地址列表时的行为有所不同,下文对不同ServerListProvider的使用条件、行为结果、优先级等特性进行说明:

1.1. 基于配置的寻址逻辑

Nacos客户端默认提供了基于配置的ServerListProvider,即PropertiesServerListProvider,该ServerListProvider会根据server-addr配置,从配置中获取服务端地址列表,若配置中存在多个服务端地址,Nacos客户端将会使用,;字符进行分割、并最终随机选择一个作为服务端地址。

若当前选择的服务端地址不可用,则Nacos客户端会按照轮询的方式,依次尝试使用其他服务端地址,当尝试所有的地址之后,会回到第一个服务端地址,继续轮询,直至找到可用的服务端地址或客户端中止。

这种寻址方式的最大优点是,Nacos客户端的配置非常简单,只需要配置server-addr即可,无需配置额外的服务端地址列表配置;同时也无需部署额外的组件;但是,这种寻址方式相对不灵活,无法动态的修改服务端地址列表,需要修改时只能重新创建一个新的Nacos客户端使用。

使用示例:

注意:不同编程语言的配置方式可能存在差异,请根据实际情况修改。

try {
// Initialize the configuration service, and the console automatically obtains the following parameters through the sample code.
String serverAddr = "{serverAddr}";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties);
NamingService configService = NacosFactory.createNamingService(properties);
} catch (NacosException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

1.2. 基于Endpoint地址服务器的寻址逻辑

Nacos客户端还提供了基于地址服务器的寻址方式,即EndpointServerListProvider,该ServerListProvider会根据endpoint配置,从endpoint所指向的地址服务器中获取服务端地址列表;

地址服务器可以是任意一个提供对应HTTP接口的服务端,例如一个nginx,tomcat服务端,Nacos的address模块等等等;对应接口需要按照格式返回Nacos服务端的地址列表,格式为每行一个地址,例如:

127.0.0.1:8848
1.1.1.1

若返回的地址没有端口,则默认端口为8848。

同样地,Nacos客户端会随机选择列表中的一个地址作为服务端地址,并使用该地址访问Nacos服务端;若该地址不可用,则Nacos客户端会按照轮询的方式,依次尝试使用其他服务端地址,当尝试所有的地址之后,会回到第一个服务端地址,继续轮询,直至找到可用的服务端地址或客户端中止。

该寻址方式的最大优点是可以动态的更新客户端所连接的服务端地址列表,无需重启客户端;但是,这种寻址方式需要额外部署一个地址服务器以提供对应的更新和获取地址列表的接口、同时可能需要配置的内容较多,适合Nacos部署规模较大的场景。

使用示例:

注意:不同编程语言的配置方式可能存在差异,请根据实际情况修改。

更多地址服务器相关配置,请参考Java SDK 配置参数-通用参数

try {
// Initialize the configuration service, and the console automatically obtains the following parameters through the sample code.
String endpoint = "{endpoint}";
Properties properties = new Properties();
properties.put("endpoint", endpoint);
ConfigService configService = NacosFactory.createConfigService(properties);
NamingService configService = NacosFactory.createNamingService(properties);
} catch (NacosException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

1.3. 不同寻址逻辑的触发优先级

当Nacos客户端启动时, 同时配置了不同的寻址逻辑,Nacos客户端会按照以下优先级进行服务端地址的获取:

  1. 优先使用EndpointServerListProvider,尝试读取endpoint相关配置,若存在,则使用EndpointServerListProvider获取服务端地址列表,endpoint相关配置默认又遵循如下优先级;
  • 1.1. 其中环境变量ALIBABA_ALIWARE_ENDPOINT_URL的优先级最高,如果存在,则使用ALIBABA_ALIWARE_ENDPOINT_URL作为地址服务器地址;
  • 1.2. 其次是初始化时传入的Properties中endpoint配置优先,如果存在,则使用endpoint所配置的地址作为地址服务器地址;
  • 1.3. 再优先是JVM参数中配置的endpoint配置优先,如果存在,则使用JVM中的endpoint所配置的地址作为地址服务器地址;
  • 1.4. 最后是环境变量中的endpoint,如果存在,使用环境变量中endpoint中配置的地址作为地址服务器地址;
  1. 若以上关于EndpointServerListProvider的配置均不存在,则使用PropertiesServerListProvider
  • 1.1. 优先使用初始化时传入的Properties中serverAddr配置,如果存在,则使用serverAddr配置的地址作为Nacos服务端地址列表;
  • 1.2. 其次是JVM参数中配置的serverAddr配置,如果存在,则使用JVM中的serverAddr配置的地址作为Nacos服务端地址列表;
  • 1.3. 最后是环境变量中的serverAddr,如果存在,使用环境变量中serverAddr中配置的地址作为Nacos服务端地址列表;

以上配置中的配置优先级顺序为默认情况下的优先级顺序, 不同的编程语言客户端的优先级可能存在差异,请根据实际情况修改;另外,如果设置了Java SDK 读取配置的优先级顺序,除了ALIBABA_ALIWARE_ENDPOINT_URL以外,其余的配置优先级顺序将会按照设置的优先级顺序进行读取。

2. 自定义的寻址方式

目前仅Java SDK支持自定义的寻址方式,其他语言的SDK暂不支持。

Nacos的Java SDK通过SPI,可以自定义ServerListProvider,实现自定义的寻址方式:

2.1. 引入依赖

<!-- 2.5.0以上的nacos-client版本支持自定义ServerListProvider -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.5.0</version>
</dependency>

2.2. 实现自定义ServerListProvider

实现接口com.alibaba.nacos.client.address.ServerListProvider

ServerListProvider的相应接口如果:

方法名入参内容返回内容描述
initNacosClientProperties, NacosRestTemplatevoid初始化时会调用此接口注入Nacos的配置,HTTP客户端等,以便于您读取初始化时传入的参数,以及通过HTTP接口访问获取其他信息等
getServerListList<String>ServerListManager会调用此接口,获取服务端地址列表
getServerNameString获取ServerListProvider所对应的服务端名称,用于标记地址列表所对应的服务端名称
getNamespaceString获取ServerListProvider所归属的命名空间,也即此Nacos客户端所归属的命名空间
getContextPathString获取ServerListProvider所对应的服务端上下文路径,当Nacos服务端配置了上下文路径时,需要此上下文路径,以便于Nacos客户端访问服务端
getOrderint获取ServerListProvider的优先级,数字越大优先级越高,EndpointServerListProvider的优先级为500,PropertiesServerListProvider的优先级为499
matchNacosClientPropertiesboolean判断当前ServerListProvider是否匹配当前Nacos客户端的配置,如果匹配,则Nacos客户端会调用init对此ServerListProvider进行初始化
isFixedboolean判断当前ServerListProvider是否所提供的地址列表是否为固定的,比如EndpointServerListProvider是可变的,PropertiesServerListProvider是固定的
getAddressSourceString获取ServerListProvider的地址列表来源地址,比如EndpointServerListProvider返回是Endpoint的地址,PropertiesServerListProvider是“(空字符串)
shutdownvoid关闭ServerListProvider,关闭时会调用此接口,以便于您关闭相关资源,比如关闭HTTP客户端等

2.3. 使用自定义ServerListProvider

添加对应的SPI配置文件META-INF/services/com.alibaba.nacos.client.address.ServerListProvider到您的resources目录中。

比如内容为:

org.example.MyServerListProvider

随后在初始化时传入的Properties中配置能让自定义ServerListProvider匹配到的对应参数,比如代码为:

public class MyServerListProvider implements ServerListProvider {
public int getOrder() {
return Integet.MAX_VALUE;
}
public boolean match(NacosClientProperties nacosClientProperties) {
return Boolean.parseBoolean(nacosClientProperties.getProperty("example.server.list.provider"));
}
}

配置内容应该为:

example.server.list.provider=true