SpringCloud 微服务注册中心 - Nacos高可用
文章目录
前言
在生产环境中,我们的nacos-server一定是集群的环境,当其中一台机器宕机时,依旧需要保证服务的可用性。Nacos 的高可用不仅仅存在于服务端,同时也存在于客户端,以及一些与可用性相关的功能特性中,这些点组装起来,共同构成了 Nacos 的高可用。Nacos会从以下几个方面去保证高可用。
- 重试机制
- 一致性协议
- 本地缓存文件 Failover 机制
- 心跳同步服务
最后我们还会介绍Nacos的集群部署配置及持久化配置。
一、重试机制
我们先说一个场景,当provider注册了两台机器 192.168.0.10和192.168.0.20 ,当某一时刻,其中10机器宕机下线,但是此时cosumer发起请求,正好请求到10机器,应该如何处理。
从处理中可用看到,逻辑非常简单,拿到地址列表,在请求成功之前逐个尝试,直到成功为止。 这个处理时在 nacos-client上处理的。
二、一致性协议
分布式一致性协议有很多,而Nacos采用的是Distro
协议和Raft
协议。
介绍一致性模型之前,需要先了解到 Nacos 中的两个概念:临时服务和持久化服务。
-
临时服务(
Ephemeral
):临时服务健康检查失败后会从列表中删除,常用于服务注册发现场景。 -
持久化服务(
Persistent
):持久化服务健康检查失败后会被标记成不健康,常用于 DNS 场景。
临时服务使用的是 Nacos 为服务注册发现场景定制化的私有协议 distro
,其一致性模型是 AP;而持久化服务使用的是 raft
协议,其一致性模型是 CP。
下面我们逐个了解一下这两个协议。
Distro协议
Distro是阿里巴巴的私有协议,目前流行的Nacos服务管理框架就采用了Distro协议。Distro 协议被定位为 临时数据的一致性协议 :该类型协议, 不需要把数据存储到磁盘或者数据库 ,因为临时数据通常和服务器保持一个session
会话, 该会话只要存在,数据就不会丢失 。
distro协议的关键点
-
distro
协议是为了注册中心而创造出的协议; -
客户端与服务端有两个重要的交互,服务注册与心跳发送;
-
客户端以服务为维度向服务端注册,注册后每隔一段时间向服务端发送一次心跳,心跳包需要带上注册服务的全部信息,在客户端看来,服务端节点对等,所以请求的节点是随机的;
-
客户端请求失败则换一个节点重新发送请求;
-
服务端节点都存储所有数据,但每个节点只负责其中一部分服务,在接收到客户端的“写“(注册、心跳、下线等)请求后,服务端节点判断请求的服务是否为自己负责,如果是,则处理,否则交由负责的节点处理;
-
每个服务端节点主动发送健康检查到其他节点,响应的节点被该节点视为健康节点;
-
服务端在接收到客户端的服务心跳后,如果该服务不存在,则将该心跳请求当做注册请求来处理;
-
服务端如果长时间未收到客户端心跳,则下线该服务;
-
负责的节点在接收到服务注册、服务心跳等写请求后将数据写入后即返回,后台异步地将数据同步给其他节点;
-
节点在收到读请求后直接从本机获取后返回,无论数据是否为最新。
distro 协议的工作流程如下
-
Nacos 启动时首先从其他远程节点同步全部数据。
-
Nacos 每个节点是平等的都可以处理写入请求,同时把新数据同步到其他节点。
-
每个节点只负责部分数据,定时发送自己负责数据的校验值到其他节点来保持数据一致性。
-
当该节点接收到属于该节点负责的服务时,直接写入。
-
当该节点接收到不属于该节点负责的服务时,将在集群内部路由,转发给对应的节点,从而完成写入。
Raft协议
Raft
协议是一种强一致性、去中心化、高可用的分布式协议,它是用来解决分布式一致性问题的,Nacos在CP的模型下,采用的就是Raft
协议.
节点角色
- Leader:负责接收客户端的请求
- Candidate:用于选举Leader的一种角色
- Follower:负责响应来自Leader或者Candidate的请求
选举时间点:
- 服务启动的时候
- leader挂了的时候
所有节点启动的时候,都是follower状态。 如果在一段时间内如果没有收到leader的心跳(可能是没有 leader,也可能是leader挂了),那么follower会变成Candidate。然后发起选举。
follower会投自己一票,并且给其他节点发送票据vote,等到其他节点回复
在这个过程中,可能出现几种情况
- 收到过半的票数通过,则成为leader
- 被告知其他节点已经成为leader,则自己切换为follower
- 一段时间内没有收到过半的投票,则重新发起选举
三、本地缓存文件 Failover 机制
注册中心发生故障最坏的一个情况是整个 Server 端宕机,这时候 Nacos 依旧有高可用机制做兜底。
一道经典的 Dubbo 面试题:当 Dubbo 应用运行时,Nacos 注册中心宕机,会不会影响 RPC 调用。这个题目大多数应该都能回答出来,因为 Dubbo 内存里面是存了一份地址的,一方面这样的设计是为了性能,因为不可能每次 RPC 调用时都读取一次注册中心,另一面,注册中心宕机后内存会有一份数据,这也起到了可用性的保障(尽管可能 Dubbo 设计者并没有考虑这个因素)。
那如果,我在此基础上再抛出一个问题:Nacos 注册中心宕机,Dubbo 应用发生重启,会不会影响 RPC 调用。如果了解了 Nacos 的 Failover 机制,应当得到和上一题同样的回答:不会。
Nacos 存在本地文件缓存机制,nacos-client
在接收到 nacos-server
的服务推送之后,会在内存中保存一份,随后会落盘存储一份快照。snapshot 默认的存储路径为:{USER_HOME}/nacos/naming/ 中.
这份文件有两种价值,一是用来排查服务端是否正常推送了服务;二是当客户端加载服务时,如果无法从服务端拉取到数据,会默认从本地文件中加载。
前提是构建 NacosNaming 时传入了该参数:namingLoadCacheAtStart=true
.
cloud:
nacos:
discovery:
naming-load-cache-at-start: true
{USER_HOME}/nacos/naming/{namespace} 下除了缓存文件之外还有一个 failover 文件夹,里面存放着和 snapshot 一致的文件夹。这是 Nacos 的另一个 failover 机制,snapshot 是按照某个历史时刻的服务快照恢复恢复,而 failover 中的服务可以人为修改,以应对一些极端场景。
四、心跳同步服务
心跳机制一般广泛存在于分布式通信领域,用于确认存活状态。一般心跳请求和普通请求的设计是有差异的,心跳请求一般被设计的足够精简,这样在定时探测时可以尽可能避免性能下降。而在 Nacos 中,出于可用性的考虑,一个心跳报文包含了全部的服务信息,这样相比仅仅发送探测信息降低了吞吐量,而提升了可用性,怎么理解呢?考虑以下的两种场景:
- nacos-server 节点全部宕机,服务数据全部丢失。nacos-server 即使恢复运作,也无法恢复出服务,而心跳包含全部内容可以在心跳期间就恢复出服务,保证可用性。
- nacos-server 出现网络分区。由于心跳可以创建服务,从而在极端网络故障下,依旧保证基础的可用性。
总结
作为注册中心,Nacos又两种节点 临时节点
和持久化节点
,分别使用了Distro
和Raft
协议,而对应的一致性模型是AP
和CP
.
Nacos在服务端和客户端采用了不同的机制保证高可用。对于我们正式环境搭建Nacos高可用架构时,我们一般会考虑部署几台机器,一般在分布式环境我们一定部署的是基数机器数量。所以结合之前的内容,distro 协议不会有脑裂问题,所以理论来说,节点数大于等于 2 即可;raft 协议的投票选举机制则建议是 2n+1 个节点。综合来看,选择 3 个节点是起码的,其次处于吞吐量和更高可用性的考量,可以选择 5 个,7 个,甚至 9 个节点的集群。