nacos应用
下载和解压
教程制作时,Nacos的最新发行版为2.1.1 (Aug 8th, 2022)(本教程就是基于这个版本),官方当前推荐的稳定版本为2.0.3。
查看最新Nacos发行版:https://github.com/alibaba/nacos/releases
并且可以在此网页上下载安装包:
下载完了之后进行解压,解压之后的目录为:
- bin目录下是启动和停止的脚本
- conf目录下是Nacos的配置文件
- 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
启动日志
我们可以访问http://localhost:8848/nacos,来访问Nacos:
默认的用户名和密码为:nacos/nacos
主页:
这个网页相当于nacos的管理台,有:
- 配置管理
- 服务管理
- 权限控制
- 命名空间
- 集群管理
配置管理
配置,其实就是一个key:value,比如
spring.datasource.username=root spring.datasource.password=root
并且我们通常会把这些配置写在application.properties或application.yml文件中,当时通过这种方式一定配置发生了改变就需要重启应用,并且通过这种方式配置的配置项仅限于当前应用,而不能做到多个应用共享。
那么nacos的配置管理功能就是来解决这些问题的,我们可以直接通过nacos管理台来新增配置,并且这些配置能够被多个应用给使用到。
新建配置
新建配置时可以指定:
Data ID:相当于一个配置文件,比如相当于application.properties,或者application-dev.properties,不过要注意的是,我们在某个项目中使用application.properties文件中,那个application表示的就是当前应用,那我们在nacos进行配置时,就要尽可能的取一些有含义的Data ID,比如user.properties(表示用户应用的配置),order.properties(表示订单应用的配置),common.properties(表示多个应用共享的配置)。
Group:在nacos中,一个Data ID,也就是一个或多个配置文件可以归类到同一个Group中,Group的作用就是用来区分Data ID相同的情况,不同的应用或中间件使用了相同的Data ID时就可以通过Group来进行区分,默认为DEFAULT_GROUP
配置内容:写具体的配置项,可以用properties的格式,也可以用yaml的格式
拉取配置
针对SpringCloud
引入依赖:
<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外,还可以配置:
spring.cloud.nacos.config.group:默认为"DEFAULT_GROUP"
spring.cloud.nacos.config.file-extension:默认为"properties"
spring.cloud.nacos.config.prefix:默认为${spring.application.name}
所以,默认情况下,会拉取"DEFAULT_GROUP"组下dataid为user.properties的配置,不过通过看源码:
// com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadApplicationConfiguration private void loadApplicationConfiguration( CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) { String fileExtension = properties.getFileExtension(); String nacosGroup = properties.getGroup(); // 1 // load directly once by default loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup, fileExtension, true); // 2 // load with suffix, which have a higher priority than the default loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true); // 3 // Loaded with profile, which have a higher priority than the suffix for (String profile : environment.getActiveProfiles()) { String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension; loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true); } }
可以发现,在拉取配置时会分为三步:
拉取dataid为user的配置
拉取dataid为user.properties的配置
拉取dataid为user-${spring.profiles.active}.properties的配置
并且优先级依次增高。
还值得注意的是,在拉取配置时,还会加上namespace这个维度取获取配置,可以通过spring.cloud.nacos.config.namespace进行配置。
我们可以在Nacos管理台:
新建不同的namespace
在每个namespace下可以进行dataid名称相同的配置
每个dataid又可以分配到不同的group下
相当于一个三层结构
拉取多个配置
一个应用可能不止需要一个配置,有时可能需要拉取多个配置,此时可以利用
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.properties
spring.cloud.nacos.config.shared-configs[0].data-id=common.properties
extension-configs表示拉取额外的配置文件,shared-configs也表示拉取额外的配置文件,只不过:
extension-configs表示本应用特有的
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属性,达到动态更新的最终效果。
历史版本回滚
可以回滚某个配置到历史版本
监听查询
监听某个配置哪些应用在使用
服务管理
服务管理核心就是:
服务注册
服务发现
通过nacos的服务注册与发现,可以使得在调用微服务时可以更加简单。
服务注册
首先,我们可以直接使用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);
以上代码表示注册一个服务:
- 服务名字为app1
- 访问该服务的地址为:11.11.11.11:8888
注意执行完上述代码后,不要上线程停掉,可以加上:
System.in.read();
运行为代码后,就可以到Nacos管理台看到:
可以发现,一个服务下:
- 一个服务可以属于某一个组,可以在注册时指定group
- 一个服务下可以有多个实例
- 一个服务下多个实例可以分为多个虚拟集群
比如以下代码就注册了一个服务有三个实例,分别属于两个虚拟集群
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();
对应的管理台展示为:
详情如下:
我们也可以使用更加定制化的方式来注册服务:
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();
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);
}
}
启动应用,就能完成服务注册:
服务消费者
也是先添加依赖:
<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);
在服务端测,如果超过15s没有收到客户端的心跳,那么就会把实例标记为不健康状态
public static final long DEFAULT_HEART_BEAT_TIMEOUT = TimeUnit.SECONDS.toMillis(15);
在服务端测,如果超过30s没有收到客户端的心跳,那么就会删除实例
public static final long DEFAULT_IP_DELETE_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
而对于持久实例,就算服务实例下线了,那么也不会被删除,我们可以通过:
spring.cloud.nacos.discovery.ephemeral=false
来配置为持久实例,表示实例信息会持久化到磁盘中去。
那什么时候用持久实例呢?我们可以发现持久实例与临时实例的区别在于,持久实例会永远在线,而临时实例不会,所以如果消费端在某种情况下想拿到已经下线的实例的实例信息,那么就可以把实例注册为持久实例。
保护阈值
在使用过程中,我们可以设置一个0-1的一个比例,表示如果服务的所有实例中,健康实例的比重低于这个比重就会触发保护,一旦触发保护,在服务消费端侧就会把所有实例拉取下来,不管是否健康,这样就起到了保护的作用,因为正常来说消费端只会拿到健康实例,但是如果健康实例占总实例比例比较小了,那么就会导致所有流量都会压到健康实例上,这样仅剩的几个健康实例也会被压垮,所以只要触发了保护,消费端就会拉取到所有实例,这样部分消费端仍然会访问到不健康的实例从而请求失败,但是也有一部分请求能访问到健康实例,达到保护的作用。
在SpringCloud Tencent中,这个功能叫“全死全活”。
权重
一个服务的多个实例,可能对应的机器配置不同,所以我们可以给不同的实例设置不同的权重,比如
给8070这个实例设置了权重为2,这样它的权重就是8071的两倍,那么就应该要承受2被的流量。
不过我们在消费一个服务时,通常是通过ribbon来进行负载均衡的,所以默认情况下nacos配置的权重是起不到作用的,因为ribbon使用的是自己的负载均衡策略,而如果想要用到nacos的权重,可以:
@Bean
public IRule ribbonRule() {
return new NacosRule();
}
这样就会利用到nacos中所配置的权重了。
Cluster(就近访问)
一个服务下会有多个实例,在nacos中,可以将这些实例指定到不同的集群中,比如可以通过:
spring.cloud.nacos.discovery.cluster-name=bj
这种方式来指定当前实例属于哪个集群,比如:
hz集群只有一个8070的实例,bj集群有8071、8072两个实例。
此时在服务消费端,也可以配置:
spring.cloud.nacos.discovery.cluster-name=bj
使得服务调用者也在bj集群,那么此时服务消费者就只会调用到bj集群中的两个实例。
如果消费端没有配置cluster-name,那么则会使用所有集群。