前言:
本文全部内容以nacos2.x为例子
一.Nacos的使用
1.nacos的安装
1) 下载nacos
第一步:直接百度搜索nacos官网,然后进入官网,在快速开始中点击nacos,然后下载
第二步:在下载页面中,选择适合自己操作系统的安装包。本章节以非源码形式启动,下载的是第二个。
第二步:本地解压缩
2)修改nacos配置,本地启动nacos
本地启动之前,需要修改nacos中的几个配置文件。
第一,修改nacos的启动脚本。由于nacos默认是集群模式启动的,我们在本地启动时候需要将启动模式改为单机启动。修改方法如下:
修改 nacos\bin\startup.cmd,将下图中的启动模式进行修改
第二,修改naco的配置文件,让配置能够持久化,方法如下。(naco默认是将配置放在了内存,没有持久化,这样每次我们改了配置,重启nacos后会丢失修改,所以我们配置nacos的持久化,让配置不会丢失。但是,本操作不影响nacos的启动,如果只是想快速入门nacos,自己跟一下流程,不进行配置也可)
·首先,在数据库中执行 mysql的脚本,脚本在 nacos\conf 下,文件名叫做 mysql-schema.sql。
·执行完sql后,在nacos\conf\application.properties中配置数据库参数
最后,启动Nacos,直接双击我们修改过的 nacos\bin\startup.cmd ,然后访问 http://localhost:8848/nacos
** 注意,不要关闭这个dos窗口 **
输入地址 http://localhost:8848/nacos 进入nacos界面如下
**nacos2默认是没有鉴权的,1.x默认有鉴权,如果是1.x启动,会先进入登录界面,用户名和密码都是 nacos**
2.使用Nacos作为注册中心
步骤一:引入依赖
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
步骤二:配置文件中添加配置
spring: application: name: rui-admin-mine profiles: # 环境配置 active: dev # 以下为naocs的配置 cloud: nacos: discovery: # 服务注册地址 server-addr: 127.0.0.1:8848
步骤三:启动类上加上注解 @EnableFeignClients注(高版本的spring-cloud不需要再加这个注解了,比如我的项目用的2021.0.8版本,就不需要加这个注解了)
做完上诉操作后,启动服务,就可以在nacos的控制台看到注册的服务了
3.使用Nacos作为配置中心
步骤一:引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
步骤二:添加配置
# tomcat server: port: 5205 # spring spring: application: name: rui-admin-mine profiles: # 环境配置 active: dev # cloud cloud: nacos: discovery: # 服务注册地址 server-addr: 127.0.0.1:8848 config: # 配置中心地址 server-addr: 127.0.0.1:8848 # 共享配置 shared-configs: - application-${spring.profiles.active}.yml - @artifactId@-${spring.profiles.active}.yml
配置讲解:spring.cloud.nacos.config.server-addr 为配置中心地址,shared-configs支持多个配置文件,每个配置文件前面用 - 分割,注意 - 后面的空格
我们在spring-cloud项目中,通常会使用bootstrap.yml作为项目内优先级最高的配置文件,如果直接在一个springboot项目下使用bootstrap.yml,会发现,项目无法识别此文件。原因是,bootstrap.yml是作为spring-cloud项目的配置文件,需要在maven中添加一个依赖才行:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
我们在配置文件中看到两种语法:
分别是$ {spring.profiles.active}和@artifactId@。${}语法用于引用一个yml文件内的属性,比如$ {spring.profiles.active},它指代的就是spring.profiles.active对应的属性--dev。所以application-${spring.profiles.active}.yml解析后 是 application-dev.yml。
另外一个语法@XXXX@ ,其中XXXX是pom.xml中的一个标签,比如,我的项目中,pom.xml中有一个buness-server,所以@artifactId@-${spring.profiles.active}.yml这一段就被解析成了buness-server-dev.yml。@@这种语法的解析发生在maven编译阶段,所以需要maven的支持,maven的pom.xml文件需要在build节点下引入如下内容:
<resources> <resource> <directory>src/main/resources</directory> <!--开启过滤,用指定的参数替换directory下的文件中的参数--> <filtering>true</filtering> </resource> </resources>
步骤三:在nacos控制台中添加配置并使用
点击打开后:
最后,在项目中正常使用配置文件即可
二.Nacos中的概念
1.数据模型
Nacos将数据模型抽象成为了三层,无论配置中心还是注册中心都是这样的结构。最顶层管理节点nameSpace,一个nameSpace下可以有多个group,一个group下可以有多个Service/DataId(注册中心里最小单元是Service,配置中心里最小单元是DataId)。这样设计的意义在于数据的隔离,不同nameSpace之间互不影响,不同group之间互不影响。不同nameSpace下可以存在相同的group。
1).namespace(命名空间): 常用场景之一是不同环境的配置的区分隔离。但是就实际开发来说,其实比较少这么做,因为dev环境和test环境以及生产环境都直接会布置不同的nacos服务
2).group(命名空间):常见场景之一是开发人员通过配置分组,让自己的本地服务在自己的分组中注册,从而避免和其他人服务在一个service下被负载均衡
3).Service/DataId(命名空间):Service对应一个服务集群,没有特殊配置会取服务的spring.application.name。DataId指代一个具体配置文件
2. 界面上每一个按钮的含义
直接参阅nacos的官方控制台手册,很详细。附链接
三.Nacos原理分析
nacos的原理需要分两部分理解,一部分是客户端(就是我们在springboot项目中引入的依赖包),一份是服务端(就是nacos服务)。
客户端是我们自己的服务在引入依赖后,启动服务时候自动装配到项目中的,服务的注册,心跳的发送,都是通过客户端先发起的。
服务端就是我们部署的nacos服务。
1.服务注册原理
客户端(Springboot项目):通过自动装配,实例化了NacosAutoServiceRegistration,NacosAutoServiceRegistration继承了ApplicationListener,通过实现onApplicationEvent,在服务启动时调用了 bind方法,bind方法底层进入了grpcClientProxy的doRegistra方法,至此,客户端以grpc方式在服务端进行了注册
服务端(Nacos服务):客户端的请求进入rpc.handler包下的InstanceRequestHandler.registerInstance。服务端代码大量运用了事件订阅发布,分支比较多,这里不聊细节流程,大家感兴趣的话可以从入口debug进去看。服务段最终做的事情是将临时实例注册到了ServiceManager的两个Map结构中。
总结:客户端通过自动装配,注入了有自动注册的bean,然后在服务启动时候,向服务端发起注册,2.x使用的是grpc的注册。服务端在接到客户端的注册请求,将service注册在一个Map结构中。
关于心跳:nacos2.x和1.x很大一个不同,心跳的实现方式变了,不再是需要客户端一直发心跳包了,而是因为有了长连接对象,服务端可以定时检查了。清除方式仍然是一定时间内,没有回应,临时实例直接从注册列表清除,而如果是永久实例,则置为不健康(1.x的nacos是客户端主动15s一次发送心跳请求给服务端,2.x改成了服务端自己起定时任务根据客户端第一次连接后产生的client对象询问客户端)
2.配置中心原理,服务如何监听到配置变更
配置中心简单来讲,在服务端会存放配置信息,并且对信息做MD5,同样,客户端也会缓存配置信息及MD5值。写操作只发生在服务端,服务端每次有变动后,就会通知所有客户端,然后客户端的配置的MD5值和服务端的MD5值比较,发现不一致则进行更新操作
3.nacos的集群数据同步及distro协议,JRaft协议
nacos是同时支持AP,CP两种架构的.AP和CP的实现,就分别是基于distro协议和JRaft协议
distro协议:对于临时实例数据开发的一种最终一致性协议。nacos在AP模式使用这种协议。它规定集群部署时,每个nacos服务间如何同步数据
1.Nacos 的每个节点是平等的,都可以处理写的请求
2.新的 Nacos节点 启动时,从其他节点同步数据
3.客户端发送的写请求,如果属于自己则处理,否则路由转发给其他节点
4.Nacos 把变更的数据异步复制到其他节点
5.每个Nacos节点只存了部分数据,定期检查客户端状态保持数据一致性
6.每个Nacos节点独立处理读请求,及时从本地发出响应。
JRaft协议:一种很有名的分布式一致性算法,nacos在CP模式中使用这种协议
此协议比较复杂,只说一下大致思路
将节点分为三种角色 leader, follower, candidata
leader :处理写请求,复制log到follower
follower:完全被动,不能发送任何请求, 只接受并响应来自 leader 和 candidate 的 message, node启动后的初始状态必须是 follower
Candidate:用来竞选一个新 leader (candidate 由 follower 触发超时而来)。
简单粗暴来说,Raft协议就是一句话:我是老大,听我的(全听leader的,同时保证leader挂了有后补)!
四.Nacos杂谈
1.开发环境协同工作时,nacos的使用
通常,在团队开发时候,nacos会在dev进行部署,配置文件统一在nacos上管理,所有人的本地服务都连接dev的nacos进行开发。
但这样有一个问题,每个人都把服务注册到了dev的nacos中,那么dev环境的nacos中每一个service都有多个节点,每次请求过来后会被负载均衡到不同开发者的本地环境。
所以在协同开发中,一般每个开发者配置文件都会修改application.name为自己的。这种开发模式要注意的是feign调用时,以及通过gateWay请求的时候,记得要换请求的path
另外一种开发模式就是,每一个开发者创建一个自己的group,服务注册在自己的group中,这种模式好处是feign调用接口不用修改,配置文件不用修改,通过gateWay调用服务时候路径不用修改,
但是这种模式需要开发者把需要调用的服务都在本地启动,并且配置文件复制一份到新的group
2.我遇到过的nacos面试问题
1)描述一下nacos的心跳机制。如果一个服务一直没有发送心跳,nacos会怎么处理?
2) 看过nacos源码吗?nacos源码中,大量使用订事件机制,能描述一下你对这种设计模式的理解吗?
3)我在本地修改nacos的配置文件后,重启服务,发现怎么都注册不上了,根据你的经验,可能是什么问题?
吐槽:当时面试问这个我懵逼了,你都知道是配置文件改错了,去检查配置文件哪里错啊!这有啥问!不过考虑面试官可能是想知道被面试者对nacos配置和nacos一些特性的使用熟练度,我随便随便说了俩,不一定对,给大家一个参考,如果不幸碰到这种离谱的问题能有个方向。
可能是namespace配置错了,nacos中namespace有两种,一种是default,一种是自己创建的,自己创建的namespace会有一个id,我们配置时候需要指定id而不是namespace名字
可能是配置文件中使用的一些占位符改动了,而联动的地方没有注意修改 比如 服务的name指定为了 @artifactId@,本地开发时候,修改服务的name为 @artifactId@-self,而其他地方有类似于${application.name}的引用,可能导致错误
4)谈谈对nacos对支持AP,CP模型的支持