一、Nacos快速入门
1.1 服务注册到Nacos
1.1.1 配置
<!-- com.alibaba.cloud--> <!-- com.alibaba.cloud--> <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的管理依赖
<!--nacos的管理依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.5.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>
修改user-service&order-service中的application.yml文件,注释eureka地址,添加nacos地址
spring: application: name: orderservice cloud: nacos: #nacos服务端地址,默认就是8848 server-addr: localhost:8848
启动nacos
我们点击服务对应的“详情”,可以准确的看到IP和端口号
二、服务多级存储模型
2.1 服务多级存储模型
多级:
一级服务(userservice)
二级集群(HZ或SH)
三级实例(例如杭州机房的某台部署了user vice的服务器)
2.2 配置实例集群属性
spring: applicaiton: name: userservice cloud: nacos: server-addr: localhost:8848 # nacos 服务端地址 discovery: cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ,杭州
启动两个userservice,那这两个userservice就是杭州集群了
那如果我想将同样的服务在再配置到上海集群呢?
复制一个user-service服务,将cluster-name修改为cluster-name: SH,然后进行启动
注意!!!这个时候不要再启动UserApplication和UserApplication2,否则将两个服务一会去SH集群
如下图所示,HZ集群,SH集群
三、NacosRule负载均衡
3.1 初了解
我们要达到的效果:order-service远程调用user-service的时候优先调用本地集群
我们还要给order-service配置一个集群属性,相当于将order-service加入到杭州集群,我们要看一看是否会先调用本地集群
此时order-service与8081、8082在相同的集群
spring: application: name: orderservice cloud: nacos: server-addr: localhost:8848 discovery: cluster-name: HZ #集群名称
当我们多次访问之后,发现8081、8082、8083都会被访问,并没有优先选择同集群的8081、8082。依旧是轮询
3.2 修改负载均衡规则
#要做配置的微服务名称 userservice: ribbon: NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
我们在order-service配置文件中修改之后再访问,发现8081,8082会有响应,而8083没有响应
假如我们把8081,8082都停掉(本地集群已经没有服务了)只留下在上海的8083,此时再发请求,依然会有响应, 原因是8083接收的请求并处理的
3.3 NacosRule负载均衡策略
优先选择同集群服务实例列表
本地集群找不到提供者,才去其他集群寻找,并且会报警告
确定了可用实例列表后,再采用随即负载均衡挑选实例
四、服务实例的权重设置
场景:
服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求
Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高权重设置为0则完全不会被访问
作用:
我们将8081,8082,8083其中的某一个停掉,用户也不会有感知。我们可以将停掉的进行版本升级,升级完成之后再进行重启(重启的时候权重不会调的很高),让少数的用户访问,以此来做测试,如果没什么问题就可以扩大权重,顺滑升级,不用半夜加班处理
权重值为0~1,权重越大则访问频率越高,权重设置为0则完全不会被访问
我在这里修改权重的时候出现了一个错误:
caused: errCode: 500, errMsg: do metadata operation failed ;caused: com.alibaba.nacos.consistency.exception.ConsistencyException: The Raft Group [naming_instance_metadata] did not find the Leader node;caused: The Raft Group [naming_instance_metadata] did not find the Leader node;
经过查找, https://www.cnblogs.com/whl-jx911/p/16736625.html这篇文章可以充分的结局上面的问题
找到nacos根目录下的data文件,删除里面的protocol文件夹
原因:Nacos 采用 raft 算法来计算 Leader,并且会记录上次启动的集群地址,所以当我们自己的服务器 IP 改变时(网络环境不稳定,如WIFI, IP 地址也经常变化),导致 raft 记录的集群地址失效,导致选 Leader 出现问题。
原因:有小伙伴,部署的nacos包,是本机运行过的,直接扔到服务器了(带着data目录),所以ip 与服务器ip不一致,导致了以上问题。
成功后如下图所示:此时8082被访问到的概率就是8081的十分之一
五、namespace命名空间环境隔离
nacos不仅是一个注册中心,也是一个数据中心
Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离(对服务做隔离)
将来不同命名空间的服务是不能互相访问的
同个命名空间中的多个东西还可以分组Group
5.1 创建命名空间
下面是圈起来的地方是命名空间的ID
5.2 修改application.yaml添加namespace
spring: application: name: orderservice cloud: nacos: server-addr: localhost:8848 discovery: cluster-name: HZ #集群名称 namespace: 1ebcface-cc3a-4e77-96d8-2f3f0500c317 #命名空间 dev环境
命名空间ID可以从下面进行复制
5.3 环境隔离的效果
但是我们查看dev服务,发现里面有orderservice服务
如果此时我们再用8080向其他三个userservice发起请求,则会报错
5.4 总结
六、Nacos和Eureka对比
6.1 相同部分
对于Nacos,
我们的服务提供者在启动时,都会把自己的信息提交给注册中心,而注册中心就会把这些信息保留下来
对于服务的消费者就可以找注册中心要这个服务信息,成为服务拉取或服务发现。服务消费者并不是每次发起请求都会去注册中心拉取。而是在拉取时将拉取到的服务信息缓存到列表中,接下来的一段时间就都可以不用拉取,而是直接使用列表中的缓存即可(这个列表会每隔30秒重新拉取并缓存)
消费者拿到服务列表之后,再经过负载均衡挑选一个发起远程调用
以上Nacos和Eureka是相同的
6.2 服务提供者不同的部分
它们两者的差别在于服务提供者的健康检测,nacos会把我们的服务提供者划分为临时实例和非临时实例
默认情况下所有的实例都是临时实例,临时实例和非临时实例在做健康检测的时候时不一样的
**临时实例:**临时的,将来我们可以人为的将他停掉所以在nacos做检查的时候采用的时心跳检测(与Eureka的心跳检测完全一致,每隔一段时间发一个请求到nacos,有一天不跳了,nacos就会将他从服务列表中剔除)
**非临时实例:**不会要求心跳检测,是由nacos主动发请求询问,并且nacos不会把非临时实例从列表中剔除,仅仅标记为不健康并且等着他恢复健康
6.3 服务消费者不同的部分
服务消费者也与Eureka有所差别
如果服务提供者在定时拉取服务之前已经挂掉了,那服务消费者在这一段时间内没有更新服务列表缓存(更新不够及时),岂不是一直调用的挂掉的服务?
答案并不是这个样子的
Eureka采用的时pull,Nacos采用的时pull+push
nacos做了一个消息推送,当nacos发现有服务挂掉,会立即发消息推送给服务消费者,服务消费者会迅速更新
6.4 图示
6.5 设置临时实例和非临时实例
spring: cloud: nacos: discovery: ephemeral: false # 设置为非临时实例
6.6 总结
6.6.1 相同
都支持服务注册和服务拉取
都支持服务提供者心跳方式做健康检测
6.6.2 不同
Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式(推荐使用临时实例)
临时实例心跳不正常会被剔除,非临时实例则不会被剔除
Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
七、配置管理
**实现配置热更新:**一般我们更改配置文件后需要再启动工程才能得以使用,但是一般工程启动时间较长,这样做的话效率很低(还有就是一个配置文件的内容好几个微服务都相同),如今我们可以利用Nacos实现配置统一管理,这些配置就会立马能够生效
配置管理服务: 会记录微服务中一些核心的配置放到上面去,微服务启动的时候就会读取配置管理服务上的配置,再与本地的配置结合,就可以完整的使用。我们之后修改配置就直接再配置管理中修改,配置管理发现配置改动后会立刻通知响应的微服务,微服务可以实现配置热更新并不需要重启服务
配置管理与注册中心都是由Nacos实现的
7.1 新建配置
创建的时候DataID要唯一,不能冲突,为了保证不冲突,我们可以用微服务名(微服务名不冲突)
DataId一般格式: 微服务名称-profile.yaml
profile指的是当前项目的运行环境,如dev,test,prod,根据自己的需求定即可
Group:分组,确定这个配置在哪个组里面
配置格式:一般选择YAML
配置内容:不需要把所有的配置都复制到这里来,我们只需要一些开关类型的数据、模板类的数据,简单的来说就是需要热更新配置的
7.2 微服务拉取配置
我们的项目会把nacos配置文件中的配置与本地配置做一个合并,再去做后面的动作
所以我们要先读取nacos配置文件,那怎么先读取nacos配置文件呢?
创建bootstrap.yml配置文件,优先级比application.yml配置文件高,会优先读取
7.2.1 Nacos的配置管理客户端依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
7.2.2 resource目录下添加bootstrap.yml文件
spring: application: name: userservice # 服务名称 profiles: active: dev #开发环境,这里是dev cloud: nacos: server-addr: localhost:8848 # Nacos地址 config: file-extension: yaml # 文件后缀名
7.2.3 读取配置
// 从nacos远程获取配置 @Value("${pattern.dateformat}") private String dateformat; @GetMapping("/now") public String now() { // LocalDateTime工具类 // LocalDateTime.now()获取当前时间 // format(DateTimeFormatter.ofPattern(dateformat)格式化 return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat)); }
7.3 总结
八、实现配置热更新
配置热更新就是我们的最终目标
8.1 方式一:注解@RefreshScope
@Slf4j @RestController @RequestMapping("/user") @RefreshScope public class UserController { }
我们先更改一下配置
将新的配置发布之后,我们不用重启微服务就可以读取到上面的新配置并且控制台还会有提示
8.2 方式二:@ConfigurationProperties注解
@Data @Component //注册成一个bean //prefix 前缀 只要前缀名和属性名拼接(即pattern.dateformat)能和nacos配置管理中的配置(pattern.dateformat)对应即可 @ConfigurationProperties(prefix = "pattern") public class PatternProperties { // 希望dateformat属性和配置文件一致 private String dateformat; }
@Autowired private PatternProperties properties; @GetMapping("/now") public String now() { // LocalDateTime工具类 // LocalDateTime.now()获取当前时间 // format(DateTimeFormatter.ofPattern(dateformat)格式化 return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat())); }
8.3 总结
Nacos配置更改后,微服务可以实现热更新,方式:
通过@Value注解注入,结合@RefreshScope来刷新
通过@ConfigurationProperties注入,自动刷新
注意事项:
不是所有的配置都适合放到配置中心,维护起来比较麻烦
建议将一些关键参数,需要运行时调整的参数放到nacos配置中心,一般都是自定义配置
九、多环境配置共享
某一个配置属性,在开发、生产、测试等环境下的值时一样的,如果在每个配置文件中都写一份,就会有些浪费,而且改的时候都要改
为了针对这种情况,我们希望配置一次之后,不管环境怎么改变,这个配置都能够被加载,这就是多环境共享的一个需求了。
微服务启动时会从nacos读取多个配置文件:
[spring.application.name]-[spring.profiles.active].yaml,例如:userservice-dev.yaml
[spring.application.name].yaml,例如:userservice.yaml,服务名直接跟上后缀,把环境省略掉,和环境并没有关系
对于第二种,无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件
9.1创建多环境配置
9.2 修改共享配置文件的属性
比之前多了envSharedValue
@Data @Component //注册成一个bean //prefix 前缀 只要前缀名和属性名拼接(即pattern.dateformat)能和nacos配置管理中的配置(pattern.dateformat)对应即可 @ConfigurationProperties(prefix = "pattern") public class PatternProperties { // 希望dateformat属性和配置文件一致 private String dateformat; // 再读一个环境共享属性 private String envSharedValue; }
@GetMapping("prop") public PatternProperties properties(){ // 直接将这个返回,那页面就能看到这个类中的所有东西了 return properties; }
配置完成后重启userapplication,并且其在dev环境
此时userservice(8081)工程能读到dev环境下的配置(userservice-dev.yaml),也能读取到共享配置文件的内容(userservice.yaml)
为了做对比,我们再启动一个userservice服务(8082),并且设置成test环境
也可以采用下面这个方式,推荐,因为上面那个方式修改之后还要改回来
9.3 验证结果
我们发现8081端口都可以读取到
而8082端口只能读取到环境共享属性值
dev环境8081,test环境8082都能拿到userservice.yaml文件的配置,证明此文件是被不同环境共享的
9.4 配置文件优先级问题
[服务名]-[环境].yaml >[服务名].yaml > 本地配置
本地配置的优先级最低,nacos中环境配置最高
9.5 多服务共享配置
不同微服务之间可以共享配置文件,通过下面的两种方式来指定:
9.5.1 方式1
spring: application: name: userservice # 服务名称 profiles: active: dev # 环境, cloud: nacos: server-addr: localhost:8848 # Nacos地址 config: file-extension: yaml # 文件后缀名 shared-configs: # 多微服务间共享的配置列表 - dataId: common.yaml # 要共享的配置文件id
9.5.2 方式2
spring: application: name: userservice # 服务名称 profiles: active: dev # 环境, cloud: nacos: server-addr: localhost:8848 # Nacos地址 config: file-extension: yaml # 文件后缀名 extends-configs: # 多微服务间共享的配置列表 - dataId: extend.yaml # 要共享的配置文件id
十、Nacos集群搭建
10.1 集群结构图
官方给出的Nacos集群图:
SLB:负载均衡器,将请求分发到不同的Nacos节点,就形成一个集群结构了
三台Nacos节点要实现数据的共享(整个MySQL集群,让多个nacos都去访问集群完成数据的读写)
10.2 搭建集群
三个nacos节点的地址:
节点 | ip | port |
nacos1 | 192.168.150.1 | 8845 |
nacos2 | 192.168.150.1 | 8846 |
nacos3 | 192.168.150.1 | 8847 |
搭建集群的基本步骤:
10.2.1 初始化数据库
Nacos默认数据存储在内嵌数据库Derby中,不属于生产可用的数据库。
官方推荐的最佳实践是使用带有主从的高可用数据库集群。
这里我们以单点的数据库为例来讲解。
首先新建一个数据库,命名为nacos,而后导入的nacos-server带的数据库初始化文件: ${nacoshome}/conf/nacos- mysql.sql
10.2.2 配置Nacos
添加内容,其实配置集群中每一个节点的信息
127.0.0.1:8845 127.0.0.1.8846 127.0.0.1.8847
找到数据库的配置并更改成下面的数据库配置(根据实际情况进行修改)
spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=root
10.2.3 启动
<code class="language-plaintext hljs">server.port=8845</code>
nacos2:
<code class="language-plaintext hljs">server.port=8846</code>
nacos3:
<code class="language-plaintext hljs">server.port=8847</code>
然后分别启动三个nacos节点:
<code class="language-plaintext hljs">startup.cmd</code>
10.2.4 nginx反向代理
upstream nacos-cluster { server 127.0.0.1:8845; server 127.0.0.1:8846; server 127.0.0.1:8847; } server { listen 80; server_name localhost; location /nacos { proxy_pass http://nacos-cluster; } }
spring: cloud: nacos: server-addr: localhost:80 # Nacos地址
此时下面的nacos地址也变成了80,而不是之前的8848
10.2.5 优化
本文由一叶发布,不代表一叶立场,转载联系作者并注明出处:https://yiyeo.com/jishu/329.html