1.概念
在上一个博客里讲到了使用eureka来进行服务的注册和拉取,在这一节我们使用另外一个技术来代替eureka实现这个功能,它就是nacos,比起eureka,它的功能更加的全面,可视化界面更加清爽,使用体验较高
2.Nacos启动
下载Nacos直接去官网下载就行,解压之后如下:
其中bin目录管理的就是Nacos的启动和关闭,进入该目录后,如下:
startup.cmd就是启动脚本,但是这里Nacos默认的是集群启动,而我们这里要使用的是单例启动,所以我们要采用单例启动的方式来启动Nacos服务
- 在该页面右键,在终端中打开,然后输入以下脚本:
- .\startup.cmd -m standalone
启动成功如下图所示
上面还给出了Nacos可视化界面的地址,进入该界面后,如下图
3.快速入门
在项目的父工程中引入依赖:
<!--nacos管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
在每一个服务中引入依赖:
<!--nacos客户端依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
修改配置文件:
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务的地址
Nacos默认的端口就是8848,这里声明一下方便以后修改端口
启动项目:
启动项目之后,查看Nacos提供的可视化界面可以看到项目已经被注册到Nacos中了
4.服务多级存储模型
原本我们有这样一个模型概念:
- 服务,例如之前例子里的提供用户功能的user-service,提供订单查询的order-service
- 实例,在每一个服务之下有多个实例,例如user-service:8081,user-service:8082等等
一个服务包含多个实例的模型,是我们所熟悉的,但是这样的模型存在隐患,就好比把所有鸡蛋放在一个篮子里,篮子一坏,鸡蛋全碎,一个机房被毁了,那么里面的服务全部都没了
而Nacos又在服务和实例之间增加了一层概念,叫作集群,一个服务包含多个集群,一个集群包含多个实例,这样就相当于把鸡蛋分别装在多个篮子里,一个篮子受损,只会毁坏这个篮子里的鸡蛋,把服务分别放在不同地域的机房中,比如我在北京、上海、深圳等地都准备一个机房,将不同实例分别放在这些机房中,其中,放在一个机房的实例我们就把其称为集群,这样有效降低了风险
Nacos引入这么一个集群的概念,也是为了防止跨集群调用,例如北京的实例想调用上海的实例,它会优先在本集群中查看有无能调用的实例,如果没有,再跨集群调用,毕竟跨集群所耗时间是比较长的。
4.1.配置集群属性
修改配置文件,如下:在原有的基础上添加discovery.cluster-name属性,HZ代指杭州(这个名称可以自定义)
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务的地址
discovery:
cluster-name: HZ
这里我设置了两个集群,一个HZ杭州,一个BJ北京,启动服务之后,查看Nacos可视化界面,可以看到设置成功
5.NacosRule负载均衡
实例之间调用的时候,选择方式是负载均衡,这是之前都已经说过了的,而Nacos的选择策略是同集群优先调用,如果同集群没有要调用的实例,那么再调用不同集群的实例,要想进行这种策略,得用Nacos提供的负载均衡规则
找到服务消费者order-service的配置文件,然后进行以下配置:
userService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
这里的userService是要调用的服务的名称,Nacos提供的负载均衡的策略叫作NacosRule
测试:
这里我先做了一个简单的集群分布:
- BJ集群:order-service 8080,user-service 8081,user-service 8082
- SH集群:user-service 8083
- 那么按照之前说的,如果order-service去调用user-service服务时,会优先调用同集群的8081或8082,如果同集群的8081,8082都挂掉了,那么才会去调用非同集群的8083
8081:
8082:
8083:
从上面的例子可以看出同集群的8081,8082都被调用了,非同集群的8083一次都没有被调用,NacosRule的负载均衡策略就是如此,若同集群有多个实例,则会随机调用
6.环境隔离
在分有开发环境和测试环境等多个运行环境的时候,我们可以用Nacos做一个环境隔离,不过这个不是必须的,这里做一个简单的了解
打开Nacos可视化界面的命名空间功能,可以看到默认的是public这个命名空间,接下来新建一个命名空间,点击“新建命名空间”
填写命名空间名称和描述,可以看到ID如果不填,系统就会通过UUID随机生成一个ID
创建成功,如下图:
接下来,要将服务放进这个新建的dev环境中,只需要在该服务的配置文件中添加如下配置:
- namespace后面跟的是命名空间的ID
运行之后,查看public命名空间下,发现已经没有order-service这个服务了,其已经存在dev命名空间里了
7.Nacos配置管理
之前在介绍微服务架构的基本模式时,说到一个微服务架构需要注册中心来统一管理服务,还需要一个配置中心来统一管理配置,想不到Nacos不仅有注册中心的功能,还有配置中心的功能(这是要把市场占完啊,真的卷>_<)下面我们就来看看这个Nacos的配置管理是怎么来用的
首先在使用这个配置管理之前,得要弄清楚
- 这个配置管理并不是要把所有的配置都放进去,而是只存核心配置
- 每个服务通过拉取配置管理中心的核心配置再结合自身服务中的配置,形成完整的配置
- 配置管理中心的配置支持热更新,即不需要重新启动项目就能完成配置更新
接下来进行配置中心的创建:
点击配置管理下的配置列表,然后点击加号进行新建配置管理中心
进入新建配置的页面,其中有三项必填
- 第一个Data ID是配置文件的名称,一般的命名规则是服务名称+环境.文件后缀,例如我的服务名称叫做userService,环境是开发环境dev,文件后缀名称是yaml,所以命名就是userService-dev.yaml
- 第二个是分组名称,我们这里就采用默认的就可以
- 第三个是配置内容,就如上面所说的,这里的配置内容并不是把所有的配置都写进去,而是要写的是要进行热更新的配置,一般来说就是开关类型的配置(让其为true还是false这类的配置)我这里写的是时间格式的配置
点击发布,完成创建
7.1.引入依赖
要想在项目中引入nacos的配置管理,还得先添加依赖,如下:
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
7.2.项目读取配置顺序
上图是项目启动后,读取文件的顺序,读取nacos配置文件的顺序要靠前于读取本地上的配置文件,但是要读取nacos的配置文件,要事先得获取到nacos服务的地址,才能找到nacos的服务器,才能读取nacos配置文件。但是这个nacos服务的地址,我们是配置在本地的配置文件里的,所以我们得把这个地址配置到一个读取顺序比nacos配置文件还要靠前的文件中,符合条件的文件名称叫做bootstrap.yml
7.3.创建bootstrap.yml
bootstrap.yml作为系统级的资源配置项,其优先级是要高于本地的application.yml(用户级的资源配置项)文件的
spring:
application:
name: userService # 服务名称
profiles:
active: dev # 开发环境
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
config:
file-extension: yaml # 文件后缀名
里面配置的内容有四点,其中三点“服务名称”,“开发环境”,“后缀名”三者组成了nacos配置文件的名称(之前已经创建好了),还有一个就是nacos服务的地址
这样一弄,就可以拉取到nacos的配置中心的配置了,那怎样就知道已经成功拉取到了配置中心的配置了呢?
- 那我们就要顺着配置中心的配置来看,配了什么就打印什么出来看看,刚刚在配置中心配置了时间的模版,那我们只需要写一个接口,打印出来时间,看看是不是符合配置的这个模版就可以了
在controller层添加一个接口,用来输出一下当前时间,这个时间的模版用从nacos配置文件中读取到的模板
- 通过@Value注解从配置文件中读取变量,然后赋值给dataFormat,编写接口按dataFormat里的模版输出时间
@Value("${pattern.dateformat}")
private String dataFormat;
@GetMapping("/now")
public String getNow(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dataFormat));
}
注意:
springcloud版本在2020以上的,系统不会优先自动读取bootstrap.yml文件,得加一个依赖让其自动读取,如下:
<!--开启自动读取bootstrap.yml文件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
结果:
7.4.实现Nacos热更新
上面说过Nacos作为配置中心最大的优点就是能实现配置的热更新,下面讲讲怎么实现
方式一
在@value注入的变量所在的类上添加@RefreshScope注解,这个注解允许SpringBoot项目在运行时动态的刷新配置,无需重新启动
方式二
采用@ConfigurationProperties注解,新建一个配置类,用来专门接收配置文件里的变量
新建配置类:
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}
@ConfigurationProperties注解从properties配置文件中读取配置,通过prefix属性指定配置文件中定义的properties配置的统一前缀,例如:
配置属性如下:
所以prefix前缀就是pattern,变量名是dateformat,约定前缀和变量名拼接起来就是配置属性,再用@Component将其注册到spring容器中
配置类写好了之后,在controller中注入bean,如下:
@Autowired
private PatternProperties properties;
@GetMapping("/now")
public String getNow(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));
}
}
8.Nacos多环境配置
刚刚在上面讲了,在同一环境下,各个服务之间的配置中心,现在来讲讲不同环境下的nacos配置中心怎么拉取
在Nacos配置中心里添加配置文件的时候,文件名格式是:服务名.文件后缀
- 区别于上面讲的:服务名+环境.文件后缀 添加了环境声明的文件,只能在该环境下才能被读取到,而没有添加环境的这个文件,在任何环境下都能被读取
- 配置文件详情如下:
文件配置弄好了,接下来还是像上面讲的一样,利用配置类将配置变量读取到变量中,如下
从配置文件中读取配置并封装到了envSharedValue这个变量中后,我们再写一个接口用来测试一下看看是不是读取到了就OK了,而且还能多配几个环境都来测试一下
- 我这里有一个dev环境,还有一个test环境,我们都来测试一下
dev环境:
test环境:
从上面两个例子可以看出来,在dev环境下的dateformat配置,在test环境下的服务没有读取到,而多环境共享的配置envSharedValue,两个服务都读取到了