1 Nacos
1.1 简介
Nacos
致力于帮助您发现、配置和管理微服务。Nacos
提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos
帮助您更敏捷和容易地构建、交付和管理微服务平台。Nacos
是构建以服务
为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
1.2 下载以及安装
下载地址:https://github.com/alibaba/Nacos/releases
直接点进去
根据需要选择win或者linux版本
1.2.1 Linux安装启动
把我们的
Nacos
包解压 :tar -zxvf nacos-server-1.1.4.tar.gz
cd 到我们的解压目录nacos :
cd nacos
-
进入到
bin
目录下 执行命令(启动单机
)sh startup.sh -m standalone
image.png -
访问
nacos
的服务端http://127.0.0.1:8848/nacos/index.html
,默认的用户名密码是 nocas/nocas
如下图所示:
image.png -
停止nacos在nacos/bin目录下,执行
sh shutdown.sh
image.png
1.2.2 Windowns安装启动
相关命令如下所示:
1.3 Nacos 主要特点
1.3.1 服务发现和服务健康监测
-
Nacos
支持基于DNS
和基于RPC
的服务发现。服务提供者使用原生SDK、OpenAPI
、或一个独立的Agent TODO
注册Service
后,服务消费者可以使用DNS TODO
或HTTP&API
查找和发现服务。 -
Nacos
提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos
支持传输层 (PING 或 TCP
)和应用层 (如HTTP、MySQL
、用户自定义)的健康检查。对于复杂的云环境和网络拓扑环境中(如VPC
、边缘网络等)服务的健康检查,Nacos
提供了agent
上报模式和服务端主动检测2种健康检查模式。Nacos
还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。
1.3.2 动态配置服务
- 动态配置服务可以让你以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
- 动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
- 配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
-
Nacos
提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。Nacos
还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
1.3.3 动态 DNS 服务
- 动态
DNS
服务支持权重路由,让你更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS
解析服务。动态DNS
服务还能让您更容易地实现以DNS
协议为基础的服务发现,以帮助你消除耦合到厂商私有服务发现API
上的风险。 -
Nacos
提供了一些简单的DNS APIs TODO
帮助你管理服务的关联域名和可用的IP:PORT
列表。
小节一下:
-
Nacos
是阿里开源的,支持基于DNS
和基于RPC
的服务发现。 -
Nacos
的注册中心支持CP
也支持AP
,对他来说只是一个命令的切换,随你玩,还支持各种注册中心迁移到Nacos
,反正一句话,只要你想要的他就有。 -
Nacos
除了服务的注册发现之外,还支持动态配置服务,一句话概括就是Nacos
=Spring Cloud注册中心
+Spring Cloud配置中心
1.3.4 Nacos领域模型划分以及概念详解
NameSpace
(默认的NameSpace
是public
NameSpace
可以进行资源隔离,比如我们dev
环境下的NameSpace
下的服务是调用不到prod
的NameSpace
下的微服务)
1.3.5 服务及其元数据管理
Nacos
能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA
以及最首要的 metrics 统计数据
关于Nacos数据的存储来说,支持临时也支持持久化。
关于设计来说支持CP也支持AP,对他来说只是一个命令的切换,随你玩,还支持各种注册中心迁移到Nacos,反正一句话,只要你想要的他就有。
1.4 Nacos服务端搭建
1.4.1 加入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring‐cloud‐alibaba‐nacos‐discovery</artifactId>
</dependency>
1.4.2 写注解(也可以不写) @EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class Tulingvip01MsAlibabaNacosClientOrderApplication {
public static void main(String[] args) {
SpringApplication.run(Tulingvip01MsAlibabaNacosClientOrderApplication.class, args);
}
}
附:
@EnableDiscoveryClient
和@EnableEurekaClient
- 共同点:都是能够让注册中心能够发现,扫描到该服务
- 不同点:
@EnableEurekaClient
只适用于Eureka
作为注册中心,@EnableDiscoveryClient
可以是其他注册中心
1.4.3 配置文件
注意
:server-addr
:不需要写协议
spring:
application:
name: order‐center
cloud:
nacos:
discovery:
server-addr: localhost:8848
登录Nacos看看是否有服务:
1.4.4 验证服务
验证我们的服务是否注册到我们的nacos
上
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/getServiceList")
public List<ServiceInstance> getServiceList() {
List<ServiceInstance> serviceInstanceList =
discoveryClient.getInstances("order‐center");
return serviceInstanceList;
}
1.5 Nacos配置管理
Nacos作为配置,可以做到不用重启服务而动态刷新配置
微服务接入配置中心的步骤
1.5.1 添加依赖
添加依赖包spring-cloud-alibaba-nacos-config
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring‐cloud‐alibaba‐nacos‐config</artifactId>
</dependency>
1.5.2 编写精准配置
编写配置文件,需要写一个bootstrap.yml
配置文件
配置解释 :
-
server-addr: localhost:8848
: 表示我微服务怎么去找我的配置中心 -
spring.application.name=order-center
: 表示当前微服务需要向配置中心索要order-center的配置 -
spring.profiles.active=prod
: 表示我需要向配置中心索要order-center的生产环境的配置 - 索要文件的格式为 :
${application.name}- ${spring.profiles.active}.${file-extension}
spring:
application:
name: order‐center
profiles:
active: prod
cloud:
nacos:
config:
server-addr: localhost:8848
file‐extension: yml
真正在nacos
配置中心上 就是 order-center-prod.yml
1.5.3 通用配置(shared‐dataids)
通用配置
指把该配置提取为一个公共配置yml
,提供给所有的工程使用
通过shared‐dataids
配置,越排到后面的公共配置yml优先级越高
spring:
application:
name: order‐center
profiles:
active: dev
cloud:
nacos:
config:
server-addr: localhost:8848
file‐extension: yml
#各个微服务共享的配置,注意越排到后面的公共配置yml优先级越高
shared‐dataids: common.yml,common2.yml
#支持动态刷新的配置文件
refreshable‐dataids: common.yml,common2.yml
配置优先级:
NacosPropertySource {name='order-center-dev.yml'},
NacosPropertySource {name='order-center.yml'},
NacosPropertySource {name='common2.yml'},
NacosPropertySource {name='common.yml'}
1.5.4 通用配置(ext-config)
通过ext-config
方式,同样配置到越后面的配置 优先级越高
extension-configs
是nacos-config
的jar包是2.2.6版本的,在此版本中ext-config
提示已过时
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
file‐extension: yml
extension-configs[0]:
data-id: common3.yml
group: DEFAULT_GROUP
refresh: true
extension-configs[1]:
data-id: common4.yml
group: DEFAULT_GROUP
refresh: true
或者如下:
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
file‐extension: yml
ext-config:
- data-id: common3.yml
group: DEFAULT_GROUP
refresh: true
- data-id: common4.yml
group: DEFAULT_GROUP
refresh: true
1.5.5 各个配置优先级
精准配置
>不同环境的通用配置
>不同工程的(ext-config)
>不同工程
精准配置
会覆盖 与通用配置
相同的配置,然后再和通用配置互补
spring:
application:
name: order‐center
profiles:
active: dev
cloud:
nacos:
config:
server-addr: localhost:8848
file‐extension: yml
shared‐dataids: common.yml,common2.yml
#支持动态刷新的配置文件
refreshable‐dataids: common.yml,common2.yml
ext-config:
- data-id: common3.yml
group: DEFAULT_GROUP
refresh: true
- data-id: common4.yml
group: DEFAULT_GROUP
refresh: true
上述配置 加载的优先级 :
-
order-center-dev.yml
精准配置 -
order-center.yml
同工程不同环境的通用配置 -
ext-config
: 不同工程 通用配置
common4.yml
common3.yml -
shared-dataids
不同工程通用配置
common2.yml
common.yml
1.5.6 配置动态刷新 refresh: true
1.5.6.1 核心配置
在 Spring Cloud Nacos
配置中,以项目名为前缀的配置文件(例如 spring.application.name
对应的配置)不用显式设置 refresh: true
也能动态刷新。这是因为:
- 默认动态刷新机制
Spring Cloud Nacos
对于默认加载的配置文件(如spring.application.name
对应的配置)会自动将其纳入刷新范围。这些默认配置会被标记为支持动态刷新,即使没有显式声明refresh: true
,也会在配置发生变更时触发通知并刷新上下文。 - 优先加载的项目配置
项目名相关的配置文件(如${spring.application.name}.properties
或.yaml
)通常是服务的核心配置
,Spring Cloud Nacos
自动将这些配置文件作为动态刷新的候选文件,无需额外的设置。 - 特殊处理机制
在Spring Cloud Nacos
的实现中,某些关键配置(如bootstrap.properties
或与服务名绑定的配置)是通过框架底层主动监听的,属于默认刷新的范围,因此无需单独指定refresh: true
。 -
@RefreshScope
作用
对于使用@RefreshScope
的 Bean,只要配置文件中的某些属性发生了变化,Spring Cloud Context
都会重新加载这些Bean
的实例。因此,如果项目名配置文件是默认刷新的范围,@RefreshScope
就能起到作用。
1.5.6.2 非核心配置
对于非核心配置,如果想要动态刷新配置值,就需要 refresh: true
和 @RefreshScope
那么,如果只有 @RefreshScope
而没有在 Nacos
配置中设置 refresh: true
,动态刷新是不会生效的。原因如下:
-
@RefreshScope
作用
@RefreshScope
是Spring Cloud Context
提供的一个注解,用于在配置刷新时重新创建带有该注解的Bean
。但它依赖于Spring
的上下文刷新机制(比如通过Actuator
的/refresh
端点触发),或者监听配置中心的变化事件。如果配置项没有被标记为可刷新(refresh: true
),配置中心的变化不会通知到应用,即不会触发动态刷新。 -
refresh: true
作用
这是Spring Cloud Nacos
的一个功能开关,用于指定某个配置是否支持动态刷新。只有设置了refresh: true
,当配置发生变更时,Spring Cloud Nacos
才会将变更通知到Spring
上下文中,并触发动态刷新逻辑。
缺少 refresh: true
的影响:
- 配置文件的变化不会触发刷新事件。
- 即使
Bean
上添加了@RefreshScope
,也不会重新加载配置。
特殊情况:
- 如果没有设置
refresh: true
,但通过手动调用Actuator
的/refresh
端点,也可以触发上下文刷新,从而更新@RefreshScope
的Bean
。不过这种方式并不依赖配置中心的实时通知机制。
1.6 Nacos集群模式
1.6.1 搭建Nacos集群
我们的nacosserver
(搭建三个集群端口分别为8849 ,8850,8851
)
我们以配置一台为例(8849)为例
- 修改
nacos8849/conf
文件application.properties
,配置数据库链接
spring.datasource.platform=mysql
# 数据库实例数量
db.num=1
//自己数据库的连接信息
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_test?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=root
创建一个数据库(需要自己创建一个数据库) 脚本的位子在nacos/conf/nacos-mysql.sql
- 修改
nacos8849/conf
文件 把原来的cluster.conf.example
改为
cluster.conf
文件
image.png
文件内容为如下
到此为止nacos8849
安装完成了而nacos8850
和nacos8851
同样安装
- 修改
nacos-server
的启动脚本jvm
参数
image.png
-
分别启动 8849 8850 8851
登录后查看集群管理
image.png
1.6.2 Nacos集群选举机制
Nacos
作为配置中心的功能是基于Raft
算法来实现的。
Raft
算法是分布式系统开发首选的共识算法,它通过一切以领导者为准
的方式,实现一系列值的共识和各节点日志的一致。
Raft
选举过程涉及三种角色和任期(Term):
-
Follower
:默默地接收和处理来自Leader
的消息,当等待Leader
心跳信息超时的时候,就主动站出来,推荐自己当Candidate
。 -
Candidate
:向其他节点发送投票请求,通知其他节点来投票,如果赢得了大多数(N/2+1
)选票,就晋升Leader
-
Leader
:负责处理客户端请求,进行日志复制等操作,每一轮选举的目标就是选出一个领导者;领导者会不断地发送心跳信息,通知其他节点“我是领导者,我还活着,你们不要发起新的选举,不用找个新领导者来替代我。” -
Term
:这跟民主社会的选举很像,每一届新的履职期称之为一届任期
领导选举过程
- 在初始时,集群中所有的节点都是
Follower
状态,都被设定一个随机选举超时时间(一般150ms-300ms):
image.png
-
如果
Follower
在规定的超时时间,都没有收到来自Leader
的心跳,它就发起选举:将自己的状态切为Candidate
,增加自己的任期编号,然后向集群中的其它Follower
节点发送请求,询问其是否选举自己成为Leader
:
image.png -
其他节点收到候选人A的请求投票消息后,如果在编号为1的这届任期内还没有进行过投票,那么它将把选票投给节点A,并增加自己的任期编号(当前节点即收到投票请求的节点):
image.png
- 当收到来自集群中过半节点的接受投票后,A节点即成为本届任期内
Leader
,他将周期性地发送心跳消息,通知其他节点我是Leader
,阻止Follower
发起新的选举:
image.png
选举的几种情况 :
- 第一种情况,赢得选举之后,
leader
会给所有节点发送消息,避免其他节点触发新的选举 - 第二种情况,比如有三个节点A B C。A B同时发起选举,而A的选举消息先到达C,C给A投了一票,当B的消息到达C时,已经不能满足上面提到的约束条件,即C不会给B投票,而A和B显然都不会给对方投票。A胜出之后,会给B,C发心跳消息,节点B发现节点A的
term
不低于自己的term
,知道有已经有Leader
了,于是转换成follower
- 第三种情况, 没有任何节点获得
majority
投票,可能是平票的情况。加入总共有四个节点(A/B/C/D),Node C、Node D同时成为了candidate
,但Node A投了NodeD一票,NodeB投了Node C一票,这就出现了平票split vote
的情况。这个时候大家都在等啊等,直到超时后重新发起选举。如果出现平票的情况,那么就延长了系统不可用的时间,因此raft引入了 randomizedelection timeouts来尽量避免平票情况
1.6.3 Raft 选举机制
Kafka
和 ES
集群选举机制也用到了Raft
选举算法,Kafka
选主指的是选 Broker 中的 Controller
,而 ES
选主指的是选取集群中的 Master
,它们两个的关联是 Kafka
新版本(2.8 之后)和 ES 新版本(7.0 之后),它们的选主策略都是基于 Raft 算法实现的。
1.6.3.1 什么是Raft算法
Raft
算法是一种分布式一致性算法,主要用于在分布式系统中实现数据副本的一致性。该算法是 Paxos
算法的工程实现,其主要特点是通过较为简单的算法实现分布式系统的数据一致性和高可用。
Raft
算法的核心是通过选举投票,少数人服从多数人的原则(投票过半原则),如果有一半以上的人投票给某个节点作为 Leader
,那么它就是新的 Leader
。
在 Raft 算法中,分布式系统中的所有节点被划分为三种角色:领导者(Leader)、追随者(Follower)和候选人(Candidate)
,这三者身份的转换如下:
-
leader -> follower
:倘若leader
发现当前系统中出现了更大的任期,则会进行禅让
,主动退位成follower
。这里leader
发现更大任期的方式包括:- 向
follower
提交日志同步请求时,从follower
的响应参数中获得。 - 收到了来自新任
leader
的心跳或者同步日志请求。 - 收到了任期更大的
candidate
的拉票请求。
- 向
-
follower -> candidate
:leader
需要定期向follower
发送心跳,告知自己仍健在的消息。倘若follower
超过一定时长没收到 leader 心跳时,会将状态切换为candidate
,在当前任期的基础上加 1 作为竞选任期,发起竞选尝试补位。 -
candidate -> follower
:candidate
参与竞选过程中,出现以下两种情形时会退回follower
:- 多数派投了反对票
- 竞选期间,收到了任期大于等于自身竞选任期的
leader
传来的请求
-
candidate -> leader
:candidate
竞选时,倘若多数派投了赞同票,则切换为 leader。 -
candidate -> candidate
:candidate
的竞选流程有一个时间阈值,倘若超时仍未形成有效结论(多数派赞同或拒绝),则会维持candidate
身份,将竞选任期加1,发起新一轮竞选。
1.6.3.2 Raft选举流程
Raft
算法的选举流程如下图所示:图片它的投票流程有三种:
- 竞选者向原
leader
请求投票:- 倘若该任期小于自身,拒绝,并回复自己的最新任期。
- 倘若该任期大于自身,退位为
follower
,按照follower
的模式处理该请求。
- 竞选者向
follower
请求投票:- 倘若任期落后于自己,拒绝请求,并回复自己所在的任期。
- 倘若任期大于自己,判断最后的同步日志是否够新,如果比自己新就把这一票投给竞选者,如果没有自己新则拒绝。
- 竞选者向
candidate
请求投票:- 倘若
leader
任期大于等于自己,同意此次投票,并退回follower
,按照 follower 模式处理请求。 - 如果
leader
任期小于自己,拒绝,并回复自己的最新任期。
- 倘若
每个竞选者根据以上投票来决定新的 leader
,如果有一个投票过半,那么它就升级为新的 leader
,并把这个消息同步给其他节点。否则会开启新的一轮投票,为了防止一直投票,会在开启新一轮投票时,设置的随机等待时间,和一定次数投票失败后弃权的机制,来保证投票顺利完成。