欢迎您的访问
专注架构,Java,数据结构算法,Python技术分享

Nacos入门使用教程

Nacos介绍

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现配置管理服务管理平台。

在这个介绍中,可以看出Nacos至少有三个核心功能:

  1. 动态服务发现
  2. 配置管理
  3. 服务管理

后续会分别来介绍这三个功能是怎么回事。

下载和解压

教程制作时,Nacos的最新发行版为2.1.1 (Aug 8th, 2022)(本教程就是基于这个版本),官方当前推荐的稳定版本为2.0.3。

查看最新Nacos发行版:https://github.com/alibaba/nacos/releases

并且可以在此网页上下载安装包:
image.png

下载完了之后进行解压,解压之后的目录为:
image.png

  1. bin目录下是启动和停止的脚本
  2. conf目录下是Nacos的配置文件
  3. target目录下是Nacos的jar包(启动脚本中其实就是运行的这个jar包,停止脚步中是直接kill到进程)

启动

解压完之后就可以启动Nacos了,Nacos支持单机和集群,默认是以集群模式启动,通过添加-m standalone就会以单机模式启动。

Linux/Unix/Mac

启动命令(standalone代表着单机模式运行,非集群模式):
sh startup.sh -m standalone

如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:
bash startup.sh -m standalone

Windows

启动命令(standalone代表着单机模式运行,非集群模式):
startup.cmd -m standalone

启动日志
image.png

可以发现,默认情况下Nacos占用了8848端口。

我们可以访问http://localhost:8848/nacos,来访问Nacos:

image.png

默认的用户名和密码为:nacos/nacos

登录进来后:
image.png

这个网页相当于nacos的管理台,有:

  1. 配置管理
  2. 服务管理
  3. 权限控制
  4. 命名空间
  5. 集群管理

配置管理

配置,其实就是一个key:value,比如

spring.datasource.username=zhouyu
spring.datasource.password=123456
  • 1
  • 2

并且我们通常会把这些配置写在application.properties或application.yml文件中,当时通过这种方式一定配置发生了改变就需要重启应用,并且通过这种方式配置的配置项仅限于当前应用,而不能做到多个应用共享。

那么nacos的配置管理功能就是来解决这些问题的,我们可以直接通过nacos管理台来新增配置,并且这些配置能够被多个应用给使用到。

新建配置

新建配置时可以指定:

  1. Data ID:相当于一个配置文件,比如相当于application.properties,或者application-dev.properties,不过要注意的是,我们在某个项目中使用application.properties文件中,那个application表示的就是当前应用,那我们在nacos进行配置时,就要尽可能的取一些有含义的Data ID,比如user.properties(表示用户应用的配置),order.properties(表示订单应用的配置),common.properties(表示多个应用共享的配置)。
  2. Group:在nacos中,一个Data ID,也就是一个或多个配置文件可以归类到同一个Group中,Group的作用就是用来区分Data ID相同的情况,不同的应用或中间件使用了相同的Data ID时就可以通过Group来进行区分,默认为DEFAULT_GROUP
  3. 配置内容:写具体的配置项,可以用properties的格式,也可以用yaml的格式

比如:
image.png

拉取配置

在nacos中新建完配置后,那作为一个SpringBoot应用我们如何来获取配置呢?

Java SDK

首先,我们可以直接使用Nacos提供的Java SDK来获取配置。

首先在项目中,添加如下依赖:

<dependency>
	<groupId>com.alibaba.nacos</groupId>
	<artifactId>nacos-client</artifactId>
	<version>2.1.1</version>
</dependency>

然后可以使用如下代码来获取nacos中的配置:

try {
	String serverAddr = "localhost:8848";
	String dataId = "user.properties";
	String group = "DEFAULT_GROUP";
	
	Properties properties = new Properties();
	properties.put("serverAddr", serverAddr);
	ConfigService configService = NacosFactory.createConfigService(properties);
	String content = configService.getConfig(dataId, group, 5000);
	System.out.println(content);
} catch (NacosException e) {
	
	e.printStackTrace();
}
  1. serverAddr:nacos的地址
  2. dataId:想要获取的配置文件的名字
  3. group:分组

在Java SDK中,除开有获取配置的API,同时也提供了新增、删除、监听配置的API。

我们可以通过如下代码来监听配置的变化:

try {
	String serverAddr = "localhost:8848";
	String dataId = "user.properties";
	String group = "DEFAULT_GROUP";
	Properties properties = new Properties();
	properties.put("serverAddr", serverAddr);
	ConfigService configService = NacosFactory.createConfigService(properties);
	String content = configService.getConfig(dataId, group, 5000);
	System.out.println(content);
	configService.addListener(dataId, group, new Listener() {

		public void receiveConfigInfo(String configInfo) {
			System.out.println("recieve1:" + configInfo);
		}

		public Executor getExecutor() {
			return null;
		}
	});

	
	while (true) {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
} catch (NacosException e) {
	
	e.printStackTrace();
}

剩余API,大家可以直接参考官网:https://nacos.io/zh-cn/docs/sdk.html

Spring

在真正开发时,我们不太会通过Java SDK的方式来拉取nacos中的配置,那Nacos有没有针对Spring提供一些比较好用的注解或API呢?

当然是有的。

增加一下依赖(不再需要nacos-client依赖了)

<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-spring-context</artifactId>
    <version>1.1.1</version>
</dependency>

我们可以按以下方式来配置Spring容器:

@Configuration
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
@NacosPropertySource(dataId = "user.properties", autoRefreshed = true)
@ComponentScan("com.zhouyu")
public class AppConfig {
}

很明显,通过@EnableNacosConfig注解定义了nacos的地址,通过@NacosPropertySource表示想要拉取的dataId,并且设置自动刷新(也就是配置发生了改变则会自动生效)。

那如何使用某一个具体的配置项呢:

@Component
public class UserService {

    @NacosValue("${spring.datasource.username}")
    private String username;

    public void test(){
        System.out.println(username);
    }
}

可以通过@NacosValue来使用某一具体的配置项,那@Value行不行呢?也是可以的。

之所以可以,原因是@EnableNacosConfig注解会负责把指定的dataId的配置项拉取到应用,并封装为PropertySource对象添加到Environment对象中,所以@Value也能读取到相应的配置项。

SpringBoot

如果我们使用SpringBoot,那则可以比Spring更加简单。

首先引入依赖:

<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>nacos-config-spring-boot-starter</artifactId>
    <version>0.2.12</version>
</dependency>

然后在application.properties中配置nacos的地址:

nacos.config.server-addr=127.0.0.1:8848

然后:

@SpringBootApplication
@NacosPropertySource(dataId = "user.properties", autoRefreshed = true)
public class UserApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(UserApplication.class, args);

        UserService userService = applicationContext.getBean(UserService.class);
        userService.test();
    }
}

依旧使用@NacosPropertySource来指定要拉取的配置dataId即可,就可以使用@Value或@NacosValue来获取某个具体的配置项了。

那有同学可能会想到,我们可不可以直接在application.properties文件中来配置dataid呢?确实可以:

nacos.config.server-addr=127.0.0.1:8848
nacos.config.data-id=user.properties
nacos.config.bootstrap.enable=true

不过要注意,一定得把nacos.config.bootstrap.enable设置为true,不然是不行的。

SpringCloud

如果我们是用SpringCloud,那将比SpringBoot更加简单。

引入依赖:

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
	<version>2.2.8.RELEASE</version>
</dependency>

然后在boostrap.properties文件中配置:

spring.application.name=user
spring.cloud.nacos.server-addr=127.0.0.1:8848

就可以了,因为会自动去连接nacos并获取dataid为user.properties的配置了。

到这里,我们大概知道了Nacos的配置管理是怎么用的了,接下来我们再来介绍一些配置管理更高级的功能。

按profile拉取配置

在使用spring-cloud-starter-alibaba-nacos-config时,我们除开可以配置spring.cloud.nacos.config.server-addr外,还可以配置:

  1. spring.cloud.nacos.config.group:默认为”DEFAULT_GROUP”
  2. spring.cloud.nacos.config.file-extension:默认为”properties”
  3. spring.cloud.nacos.config.prefix:默认为${spring.application.name}

所以,默认情况下,会拉取”DEFAULT_GROUP”组下dataid为user.properties的配置,不过通过看源码:



private void loadApplicationConfiguration(
	CompositePropertySource compositePropertySource, String dataIdPrefix,
	NacosConfigProperties properties, Environment environment) {
	String fileExtension = properties.getFileExtension();
	String nacosGroup = properties.getGroup();

	
	
	loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
						   fileExtension, true);

	
	
	loadNacosDataIfPresent(compositePropertySource,
						   dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
	
	
	
	for (String profile : environment.getActiveProfiles()) {
		String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
		loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
							   fileExtension, true);
	}

}	

可以发现,在拉取配置时会分为三步:

  1. 拉取dataid为user的配置
  2. 拉取dataid为user.properties的配置
  3. 拉取dataid为user-${spring.profiles.active}.properties的配置

并且优先级依次增高。

还值得注意的是,在拉取配置时,还会加上namespace这个维度取获取配置,可以通过spring.cloud.nacos.config.namespace进行配置。

我们可以在Nacos管理台:

  1. 新建不同的namespace
  2. 在每个namespace下可以进行dataid名称相同的配置
  3. 每个dataid又可以分配到不同的group下

相当于一个三层结构

拉取多个配置

一个应用可能不止需要一个配置,有时可能需要拉取多个配置,此时可以利用

  1. spring.cloud.nacos.config.extension-configs[0].data-id=datasource.properties
  2. spring.cloud.nacos.config.shared-configs[0].data-id=common.properties

extension-configs表示拉取额外的配置文件,shared-configs也表示拉取额外的配置文件,只不过:

  1. extension-configs表示本应用特有的
  2. shared-configs表示多个应用共享的

注意优先级:

  • extension-configs[2] > extension-configs[1] > extension-configs[0
  • shared-configs[2] > shared-configs[1] > shared-configs[0]
  • 主配置 > extension-configs > shared-configs

配置的自动刷新

默认情况下,主配置会自动刷新,extension-configs和shared-configs不会自动刷新,可以通过spring.cloud.nacos.config.refresh-enabled=false来关闭主配置的自动刷新。

自动配置的意思是,一旦应用中引入的配置发生了变化,应用端也能及时获取到最新值。

值得注意的是,尽管默认情况下会自动刷新,但是对于通过@Value的使用方式,还需要在该Bean上加上**@RefreshScope注解**,这样才能动态的修改@Value属性,达到动态更新的最终效果。

历史版本回滚

可以回滚某个配置到历史版本

监听查询

监听某个配置哪些应用在使用

服务管理

服务管理核心就是:

  1. 服务注册
  2. 服务发现

通过nacos的服务注册与发现,可以使得在调用微服务时可以更加简单。

Java SDK

服务注册

首先,我们可以直接使用Nacos提供的Java SDK来进行服务注册。

首先在项目中,添加如下依赖:

<dependency>
	<groupId>com.alibaba.nacos</groupId>
	<artifactId>nacos-client</artifactId>
	<version>2.1.1</version>
</dependency>

我们可以使用如下代码来快速的进行服务注册:

NamingService naming = NamingFactory.createNamingService("localhost:8848");
naming.registerInstance("app1", "11.11.11.11", 8888);

以上代码表示注册一个服务:

  1. 服务名字为app1
  2. 访问该服务的地址为:11.11.11.11:8888

注意执行完上述代码后,不要上线程停掉,可以加上:

System.in.read();

运行为代码后,就可以到Nacos管理台看到:
image.png

可以发现,一个服务下:

  1. 一个服务可以属于某一个组,可以在注册时指定group
  2. 一个服务下可以有多个实例
  3. 一个服务下多个实例可以分为多个虚拟集群

比如以下代码就注册了一个服务有三个实例,分别属于两个虚拟集群

NamingService naming = NamingFactory.createNamingService("localhost:8848");
naming.registerInstance("app1", "11.11.11.11", 8888, "cluster1");

NamingService naming1 = NamingFactory.createNamingService("localhost:8848");
naming1.registerInstance("app1", "11.11.11.12", 8888, "cluster1");


NamingService naming2 = NamingFactory.createNamingService("localhost:8848");
naming2.registerInstance("app1", "11.11.11.13", 8888, "cluster2");

System.in.read();

对应的管理台展示为:
image.png

详情如下:
image.png

我们也可以使用更加定制化的方式来注册服务:

NamingService naming = NamingFactory.createNamingService("localhost:8848");

Instance instance = new Instance();
instance.setIp("55.55.55.55");
instance.setPort(9999);
instance.setHealthy(false);
instance.setWeight(2.0);
Map<String, String> instanceMeta = new HashMap<String, String>();
instanceMeta.put("site", "et2");
instance.setMetadata(instanceMeta);

naming.registerInstance("app1", instance);

System.in.read();

以上代码注册了一个不健康的实例,并且设置了权重和元数据, 对应的管理台效果为:
image.png

服务发现

服务注册之后,服务消费者就可以来使用了,我们可以使用如下api来获取某个服务的所有实例信息

NamingService naming = NamingFactory.createNamingService("localhost:8848");
System.out.println(naming.getAllInstances("app1"));

也可以获取所有健康的实例

naming.selectInstances("app1", true)

可以直接某一个健康的实例(权重随机算法)

naming.selectOneHealthyInstance("app1")

通常,作为服务消费者,还需要监听服务实例化的变化,我们可以使用如下api来监听变化:

NamingService naming = NamingFactory.createNamingService("localhost:8848");
naming.subscribe("app1", event -> {
	if (event instanceof NamingEvent) {
		System.out.println(((NamingEvent) event).getServiceName());
		System.out.println(((NamingEvent) event).getInstances());
	}
});

以上是Nacos提供了Java SDK的常用API,熟悉这些API能更好的理解或深入研究Nacos。

Spring/SpringBoot

直接使用Java SDK的方式来进行服务注册和发现比较麻烦,不过目前在Spring和SpringBoot中使用也不怎么方便,可以自行参考官网的教程:https://nacos.io/zh-cn/docs/quick-start-spring-boot.html

SpringCloud

我们直接来看SpringCloud中如何使用Nacos来进行服务注册和发现

首先添加依赖:

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
	<version>2.2.8.RELEASE</version>
</dependency>

服务提供者

在服务提供者的application.properties中配置:

server.port=8070
spring.application.name=service-provider

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

使用@EnableDiscoveryClient来开启服务注册

@SpringBootApplication
@EnableDiscoveryClient
public class UserApplication {

	public static void main(String[] args) throws IOException {
		SpringApplication.run(UserApplication.class, args);
	}
}

启动应用,就能完成服务注册:
image.png

服务消费者

也是先添加依赖:

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
	<version>2.2.8.RELEASE</version>
</dependency>

再配置应用的application.properties文件:

server.port=8080
spring.application.name=service-consumer

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

然后使用@EnableDiscoveryClient开启服务发现:

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {

	public static void main(String[] args) {
		SpringApplication.run(ConsumerApplication.class, args);
	}
}

然后通过定义一个RestTemplate来发现http请求,并使用@LoadBalanced

@LoadBalanced
@Bean
public RestTemplate restTemplate() {
	return new RestTemplate();
}

然后来使用RestTemplate调用服务:

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;


    @GetMapping(value = "/test")
    public String echo() {
        return restTemplate.getForObject("http://service-provider/test", String.class);
    }
}

可以发现在SpringCloud中使用Nacos还是比较方便的。

高级功能

接下来我们再来看看Nacos服务管理中一些比较高级的功能

临时实例与持久实例

默认情况下,注册给nacos的实例都是临时实例,临时实例表示会通过客户端与服务端之间的心跳来保活,默认情况下,客户端会每隔5s发送一次心跳

public static final long DEFAULT_HEART_BEAT_INTERVAL = TimeUnit.SECONDS.toMillis(5);
  • 1

在服务端测,如果超过15s没有收到客户端的心跳,那么就会把实例标记为不健康状态

public static final long DEFAULT_HEART_BEAT_TIMEOUT = TimeUnit.SECONDS.toMillis(15);
  • 1

在服务端测,如果超过30s没有收到客户端的心跳,那么就会删除实例

public static final long DEFAULT_IP_DELETE_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
  • 1

而对于持久实例,就算服务实例下线了,那么也不会被删除,我们可以通过:

spring.cloud.nacos.discovery.ephemeral=false
  • 1

来配置为持久实例,表示实例信息会持久化到磁盘中去。

那什么时候用持久实例呢?我们可以发现持久实例与临时实例的区别在于,持久实例会永远在线,而临时实例不会,所以如果消费端在某种情况下想拿到已经下线的实例的实例信息,那么就可以把实例注册为持久实例。

保护阈值

在使用过程中,我们可以设置一个0-1的一个比例,表示如果服务的所有实例中,健康实例的比重低于这个比重就会触发保护,一旦触发保护,在服务消费端侧就会把所有实例拉取下来,不管是否健康,这样就起到了保护的作用,因为正常来说消费端只会拿到健康实例,但是如果健康实例占总实例比例比较小了,那么就会导致所有流量都会压到健康实例上,这样仅剩的几个健康实例也会被压垮,所以只要触发了保护,消费端就会拉取到所有实例,这样部分消费端仍然会访问到不健康的实例从而请求失败,但是也有一部分请求能访问到健康实例,达到保护的作用。

在SpringCloud Tencent中,这个功能叫“全死全活”

权重

一个服务的多个实例,可能对应的机器配置不同,所以我们可以给不同的实例设置不同的权重,比如
image.png
给8070这个实例设置了权重为2,这样它的权重就是8071的两倍,那么就应该要承受2被的流量。

不过我们在消费一个服务时,通常是通过ribbon来进行负载均衡的,所以默认情况下nacos配置的权重是起不到作用的,因为ribbon使用的是自己的负载均衡策略,而如果想要用到nacos的权重,可以:

@Bean
public IRule ribbonRule() {
	return new NacosRule();
}
  • 1
  • 2
  • 3
  • 4

这样就会利用到nacos中所配置的权重了。

Cluster(就近访问)

一个服务下会有多个实例,在nacos中,可以将这些实例指定到不同的集群中,比如可以通过:

spring.cloud.nacos.discovery.cluster-name=bj
  • 1

这种方式来指定当前实例属于哪个集群,比如:

image.png

hz集群只有一个8070的实例,bj集群有8071、8072两个实例。

此时在服务消费端,也可以配置:

spring.cloud.nacos.discovery.cluster-name=bj
  • 1

使得服务调用者也在bj集群,那么此时服务消费者就只会调用到bj集群中的两个实例。

如果消费端没有配置cluster-name,那么则会使用所有集群。

集群部署

在前面,我们都是使用的单机模式部署的nacos服务端的,为了保证nacos的高可用,也就是保证配置中心和注册中心的高可用,通常我们都需要以集群的方式来部署nacos server。

首先,我们修改conf/cluster文件,把nacos集群中所有的节点的ip和port配置进去:

192.168.65.46:8848
192.168.65.46:8858
192.168.65.46:8868
  • 1
  • 2
  • 3

我这里是在我本机搭集群,所以ip地址一样,端口得不一样,如果大家是在多个机器上搭机器,则ip地址不一样,端口可以一样,也可以不一样,通常是一样(8848)。

如果多个机器来搭集群,那么这么配置一下就可以了,注意每个机器上得cluster文件都要配,表示每个nacos节点都得知道自己所在集群的节点情况。

我这里在本地搭,就需要多几个步骤。

先复制三份
image.png
每个文件夹的内容都是如下
image.png

分别修改三个cluster文件的内容都为:

192.168.65.46:8848
192.168.65.46:8858
192.168.65.46:8868
  • 1
  • 2
  • 3

再分别修改三个application.properties中的server.port为8848、8858、8868

然后通过cmd分别进去三个文件夹中的bin目录,运行:

startup.cmd -p embedded
  • 1

来启动三个节点

启动成功后
image.png

然后我们就可以通过:http://localhost:8848/nacoshttp://localhost:8858/nacoshttp://localhost:8868/nacos这三个路径来访问nacos管理台,效果是一样的。

并且可以看到集群的情况:
image.png

不过我们我们在启动的时候,使用了

startup.cmd -p embedded
  • 1

表示使用内置数据源,我们可以切换成mysql,首先我们在自己的mysql中新建一个schema:nacos_config

然后执行image.png
然后执行该sql脚本,去创建相关的表,可以发现只有配置中心的配置信息才会存到mysql中,注册中心的服务信息是不会存的。

然后修改application.properties文件中的:

### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos2?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=Zhouyu123456***
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

三个节点都配好,并且必须连接同一个数据库,配好之后,就可以直接使用startup.cmd来启动了。

那nacos集群搭建完之后,对应我们的应用而言,连接任意一个节点都可以,或者可以配置配多个:

spring.cloud.nacos.discovery.server-addr=192.168.65.46:8848, 192.168.65.46:8858, 192.168.65.46:8858
  • 1

这样其中某个节点就算挂掉了,对于应用而言也能从其他节点获取信息。

不过,在应用上指定多个ip地址,有一个缺点就是,如果一旦ip地址发生变化,那么就得修改,所以我们可以在nacos集群之上在搭一个nginx。

先下载一个nginx,然后修改conf/nginx配置文件:

添加upstream

upstream nacos-cluster {
	server 192.168.65.46:8848;
    server 192.168.65.46:8858;
    server 192.168.65.46:8868;
}
  • 1
  • 2
  • 3
  • 4
  • 5

添加location:

location /nacos {
	proxy_pass http://nacos-cluster;
}
  • 1
  • 2
  • 3

启动nginx后,访问http://localhost/nacos就可以访问到nacos管理台了,并且在应用中只需要配置:

spring.cloud.nacos.discovery.server-addr=localhost:80/nacos

即可进行服务注册与发现。

赞(0) 打赏
版权归原创作者所有,任何形式转载请联系作者;码农code之路 » Nacos入门使用教程

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏