目录
一、Nacos,启动!
1、安装 Nacos
2、运行 Nacos
3、Nacos 服务注册
二、Nacos 服务多级存储模型
1、服务跨集群分配
2、NacosRule 负载均衡(优先本地)
3、服务实例的权重设置
4、环境隔离
三、Nacos 注册中心细节分析
1、临时实例与非临时实例
2、Nacos 和 Eureka 的对比
四、Nacos 配置管理
1、统一配置管理
2、微服务配置拉取
3、配置热更新
4、多环境配置共享
5、Nacos 集群搭建
6、配置管理问题汇总
Nacos 跟 Eureka 一样,都是服务注册中心。我们可以选择使用 Nacos,也可以选择使用 Eureka。
1、安装 Nacos
Nacos 的版本选择 1.x 的版本,因为 2.x 的已经停止维护了。
注意:一定是带有 server 的,不是 develop、client 之类的。
gitee 链接:https://gitee.com/manic-little-er/nacos-server-1.4?_from=gitee_search
2、运行 Nacos
(1)查看端口
- 打开 conf 目录下的 application.properties 文件中;
- 其中写有端口号为 8848,若后续启动失败,有可能是端口被占用了;
(2)运行 startup.cmd
- 现在我们的环境是单机,在 bin 目录下打开控制台,输入:startup.cmd -m standalone;
(3)访问 Nacos 控制页面
- 在刚才的控制台中有 Nacos 的控制页面的链接:localhost:8848/nacos/index.html;
- 访问后是一个登录页面,账号、密码都是:nacos;
3、Nacos 服务注册
现在有 2 个 service 模块:order-service 和 user-service。其中,order-service 会调用 user-service。
相关代码可以查看:https://blog.csdn.net/joyride_run/article/details/134031277
(1)引入依赖
- 在父工程的 pom 文件中引入 spring-cloud-alibaba;(也可以按照自己的项目引入到 pom 文件)
- springcloud 版本为 2021.0.6,推荐使用 springcloud-alibaba 的版本为 2021.1;
- 在被调用的 user-service 模块中,引入 nacos 客户端依赖包;(也可以引入到父工程的 pom)
- 这样 Nacos 就会创建出 user-service 服务实例;
(2)修改 application 配置文件
- 在 order-service 模块的 application 中,添加 server-addr 的属性;
- 在 user-service 模块的 application 中,添加 server-addr 的属性;
(3)启动 application,观察服务列表
- 启动 application;
- 在这之前还需要启动 nacos 的服务端;
二、Nacos 服务多级存储模型
一个服务可以有多个实例。比如上面的 user-service 有 2 个实例。假如服务器出现故障,那么部署在这个服务器中的所有实例,都会被销毁。
为了解决这个问题,Nacos 参考了现实中的方法,将多个实例当作同一个机房内的服务,也叫做集群。这就形成了多级存储模型:
服务 -> 集群 -> 实例
1、服务跨集群分配
- 现实中的服务器一般会分布在不同的地域,如果服务想要获取实例时,不从本地获取(局域网),反而去到别的集群获取,就会大大增加延迟,降低效率。
- 只有在本地集群不可用时,才会考虑其他集群。
(1)为 Nacos 设置集群
- 打开 Nacos 控制面板,启动 order-service;
- 会发现它的集群为 default;
(2)修改 application 配置文件
- 配置 cluster-name 属性,属性值代表集群名称;
(3)启动 application,观察 Nacos 服务列表
- 可以发现,2 个 order-service 的实例,都已经是 BJ 集群;
(4)同服务分配到不同集群
如果我们想将 2 个 order-service 实例的其中之一,分配到 SH(上海)集群,应该怎么做呢?
- 将其中一个 application 关闭,然后修改 application 配置文件;
- 再次观察 order-service 的详细信息,会发现已经分为不同的集群;
2、NacosRule 负载均衡(优先本地)
需求:
order-service 实例优先调用本地集群的 user-service,当本地集群一个 user-service 实例都没有时,访问别的集群。
我们设计出如下集群:
(1)修改 application 配置文件
- 将 order-service 对 user-service 的负载均衡规则修改为 NacosRule;
(2)发起请求 /order/queryOrderById/xxx
- 只有 user-service1 和 user-service2 有输出,user-service3 无输出;
(3)访问 user-service3
- 将 order-service 本地集群的 2 个 user-service 关闭;
- 再次发起请求,观察 user-service3 是否有输出;
- user-service3 有输出,说明跨集群调用生效;
- order-service 中同样有跨集群调用的提示;
(4)NacosRule 同集群内调用
- NacosRule 确定了采用哪个集群的服务列表后,不是使用轮巡负载均衡规则,而是使用随机负载均衡规则。
3、服务实例的权重设置
实际部署中会出现这样的场景:
- 服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求
Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高。
这样做的好处就在于:
- 当我们需要版本升级、维护机器等操作时,可以先将目标服务器的权重设置为 0,待服务器完全不承担用户请求的时候,就可以将其停机。
4、环境隔离
在实际开发中,通常会有不同的生产环境,对于某个服务,可以为其分配到指定的命名空间,这样其他命名空间的服务,就访问不到它。
namespace:
- Nacos 中服务存储和数据存储的最外层都是一个名为 namespace 的东西,用来做最外层隔离。
- 同一个命名空间内有 group,分组后,就可以在每个 group 中存放 service 或者 data。
(1)查看 namespace
- 在 nacos 控制页面中,左侧选项就可以查看 namespace;
- 在默认情况下,我们的 service/data 都属于 public 命名空间下的 default_group ;
(2)新建 namespace
- 在 namepace 的右侧,可以选择新建 namespace;
- 创建一个用于开发环境的 namespace;
- ID 如果不填写,会自动使用 UUID 生成;
(3)为 service 配置 namespace 属性
- 要想我们的 service 能注册到新的 namespace 上,需要在 application 中去配置;
- 配置 namespace 的时候,属性值写的是 ID;
三、Nacos 注册中心细节分析
1、临时实例与非临时实例
从上图可以看出:
- 临时实例是由提供者周期发送心跳,来维持服务的提供;(服务停止,Nacos 会删除它)
- 非临时实例是由 Nacos 来主动进行查询;(服务停止,Nacos 不会删除它)
(1)配置非临时实例
(2)启动 application
2、Nacos 和 Eureka 的对比
(1)Nacos 与 Eureka 的共同点
- 都支持服务注册和服务拉取;
- 都支持服务提供者心跳方式做健康检测;
(2)Nacos 与 Eureka 的区别
- Nacos 支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式;
- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除;
- Nacos 支持服务列表变更的消息推送模式,服务列表更新更及时;
- Nacos 集群默认采用 AP 方式,当集群中存在非临时实例时,采用 CP 模式;Eureka采用 AP 方式;
四、Nacos 配置管理
实际开发中,会有很多的微服务,当需要修改配置的时候,得一个一个地去修改配置文件,非常麻烦,并且修改完成后还需要重启服务。
因此 Nacos 的配置管理,通常用来配置一些经常需要热更新的属性。
1、统一配置管理
我们在 Nacos 写好统一配置后,微服务会自动读取配置,然后注册到 Nacos。
可以简单理解为:service 读取 Nacos 的统一配置文件后,接着读取本地 application 配置文件,相当于将两个配置文件合并。
(1)在 public 命名空间中新建一个配置
- 也可以选择在自己创建的 namespace 中新建;
- 比如我这里就自己创建有 development 命名空间;
(2)填写相关信息
- DataID:由服务名称和开发环境组成,格式为 yaml;
- 一般是:[服务名称]-[profile].yaml;
(3)编写配置文件
- 基于前面所述的内容,统一配置显然不是把一个 service 的配置文件的内容全都复制过来;
- Nacos 内的统一配置一般用来热更新(比如一些开关类型、模板类型的属性);
2、微服务配置拉取
前面说到,service 启动会先读取 Nacos 的配置文件,那么这里就有个问题,service 要怎么知道 Nacos 配置文件的地址呢?
这里就要引入一个配置文件:bootstrap.yml。它的优先级要比 application.yml 高,可以在 bootstrap.yml 内写上关于 Nacos 的相关信息。
下面我们为 user-service 获取统一配置。
(1)引入 Nacos 的配置管理客户端依赖
- 哪个 service 模块需要统一配置,哪个模块就引入;(也可以引入到父工程的 pom)
- 因为前面配置的是 user-service,所以我们引入到 user 模块;
(2)添加 bootstrap.yml 文件
- 在 userservice 中的 resource 目录添加一个 bootstrap.yml 文件;
- 这个文件是引导文件,优先级高于 application.yml;
- 明确地址,明确文件名,借助这些信息,就可以找到 Nacos 统一配置文件;
- 那么在 application 中,重复的内容就可以删除了;
(3)读取 Nacos 统一配置的内容
- 如何证明读取到了统一配置文件?
- 只需要输出其中的内容即可证明;
- 使用 @Value 注解可以读取配置文件;
(4)启动 application,访问 /user/nowDate
- 启动的时候只需要启动 user 的 application 即可;
- 如果启动了其他依赖了 user 的 service,是会报错的;
- 因为我们没有给其他的 service 编写 bootstrap 配置文件;
3、配置热更新
只靠前面的配置,是无法让微服务自动读取配置文件的变更内容的。
可以发现,我们修改了配置文件内容之后,调用服务,并没有发生相关变化。
我们需要以下 2 种方法实现热更新:
(1)@RefreshScope + @Value
通常在 SpringCloud 工程中,可以使用 @RefreshScope + @Value 实现配置文件内容变更后的动态刷新。
重新启动服务,访问一次后,再次修改配置文件,再次访问。
(2)使用 @ConfigurationProperties(推荐使用)
- 首先创建一个配置属性类,类的属性就是配置文件中的属性;
- @Component:让 Spring 识别,将其作为一个 bean 加入 IOC 中;
- @Data 提供了 set、get 等方法;
- 自动注入 Properties 类,get 方法获取属性;
4、多环境配置共享
考虑这么一个问题:
- 比如测试、开发、生产等环境,他们有着一部分相同的配置信息,如果给每一环境都这么写上配置文件,不仅前期编写麻烦,后期修改也麻烦。
因此我们需要一个任何环境下都能被加载的配置。
(1)Nacos 读取的配置文件
微服务启动时会从 nacos 读取 2 个配置文件:
- [spring.application.name]-[spring.profiles.active].yaml,例如: user-service-dev.yaml
- [spring.application.name].yaml,例如: user-service.yaml
无论 profile 如何变化,[spring.application.name].yaml 这个文件一定会加载,因此多环境共享配置可以写入这个文件。
(2)编写共享配置文件
- ID 取为 [spring.application.name].yaml;
- 在配置内容中设置一个共享属性值;
(3)测试代码
- 直接返回一个 properties 属性类,SpringMVC 会将其转为 JSON;
(4)访问 /user/properties
下面开启 2 个不同的端口,运行在不同的环境:
- 在 8081 端口启动一个环境为 development 的 application;
- 可以获取到 2 个属性值;
- 在 8082 端口启动一个环境为 test 的 application;
- 可以获取到 1 个属性值,获取不到 development 环境下的 dateformat;
(5)多种配置文件有相同属性时的优先级
5、Nacos 集群搭建
在企业中,更强调高可用性,Nacos 一定要做成集群的模式,由负载均衡器将请求发送到不同的 Nacos 节点。
https://www.bilibili.com/video/BV1LQ4y127n4/?p=29
6、配置管理问题汇总
(1)无法获取 Nacos 配置文件的内容
如下图所示:
确定几个方面:
- 添加了 bootstrap 起步依赖,高版本默认是不添加的;
- 服务集群和配置文件是同一个 namespace;
- 配置文件没有写错;