Nacos config原理
一、Nacos Config与Spring Cloud Config原理对比
说到Nacos Config配置中心的原理,就不得不提一下Spring Cloud Config配置中心的原理,二者是如此的相似,但却也有着很多不同的特点。
1、Spring Cloud Config原理
(1)提交配置触发post请求给server端的bus/refresh接口
(2)server端接收到请求并发送给Spring Cloud Bus总线
(3)pring Cloud bus接到消息并通知给其它连接到总线的客户端
(4)其它客户端接收到通知,请求Server端获取最新配置
(5)全部客户端均获取到最新的配置
2、Nacos Config工作原理
(1)客户端发起长轮训请求
(2)服务端收到请求以后,先比较服务端缓存中的数据是否相同
如果不同,则直接返回
如果相同,则通过schedule延迟30s之后再执行比较。3. 为了保证当服务端在30s之内发生数据变化能够及时通知给客户端,服务端采用事件订阅的方式来监听服务端本地数据变化的事件,一旦收到事件,则触发通知把结果写回到客户端,完成一次数据的推送
(3)为了保证当服务端在30s之内发生数据变化能够及时通知给客户端,服务端采用事件订阅的方式来监听服务端本地数据变化的事件,一旦收到事件,则触发通知把结果写回到客户端,完成一次数据的推送
3、两种配置中心对比
Nacos Config 无需消息总线系统,系统搭建成本与复杂度比 SpringCloud Config 低很多。
Nacos Config 不会一窝蜂向配置中心索要配置信息,Nacos Config是定点更新。
Nacos Config 有远程配置更新后,会自动更新到 client。其采用了长轮询 Pull 模型。而Spring Cloud Config 则需要 client 提交请求。
二、Nacos Config中的长轮询Pull模型
配置中心Server和客户端Client实现配置的动态感知一般无外乎两种办法:
一种是Client发起,叫pull模式
一种是Server发起,叫push模式
长轮询中Push模式和Pull模式的对比:
若使用 Push 模型,需要在 Server 与 Client 间通过心跳机制维护一个长连接。这个长连接的维护成本是比较高的。其适合于 Client 数量不多,且 Server 端数据变化较频繁的场景。优点:数据更新很及时。
若使用 Pull 模型,其无需维护长连接【29.5s】,但其实时性不好。
Nacos 采用的是长轮询机制的 Pull 模型,但不单纯是Pull模型。是一个HttpPost的长轮询,过期时间默认是30S。
Nacos 长轮询 Pull 模型融合了 Push 与 Pull 模型的优势。Client 仍定时发起 Pull 请求,查看 Server 微服务框架 端数据是否更新。若发生了更新,则 Server 立即将更新数据以响应的形式发送给 Client 端;若没有发生更新,Server 端并不立即向 Client 返回响应,而是临时性的保持住这个连接一段时间【29.5s】。若在此时间段内,Server 端数据发生了变更,则立即将变更数据返回给 Client【这里是动态感知的】。若仍未发生变更,则放弃这个连接。等待着下一次 Client 的 Pull 请求。
长轮询 Pull 模型,是 Push 与 Pull 模型的整合,既降低了 Push 模型中长连接的维护问题,又降低了 Push 模型实时性较低的问题。
三、Nacos采用的Raft算法及集群选举
1、CAP
目前应用的比较多的注册中心,Eureka 是 AP 的,Zookeeper 是 CP 的。默认情况下,Nacos Discovery 集群是 AP的。但其也支持 CP 模式,需要进行转换。若要转换为 CP 的,可以提交如下 PUT 请求,完成 AP 到 CP 的转换。
http://localhost:8848/nacos/v1/ns/operator/switches?entry=ServerMode&value=CP
2、Raft算法
Nacos Discovery 集群为了保证集群中数据的一致性,其采用了 Raft 算法。这是一种通过对日志进行管理来达到一致性的算法。Raft 通过选举 Leader 并由 Leader 节点负责管理日志复制来实现各个节点间数据的一致性。
Raft算法是一个最终一致性的算法,不是强一致性算法。Raft 算法动画演示:http://thesecretlivesofdata.com/raft/
3、Raft Leader选举
在 Raft 中,节点有三种角色:
Leader【主】:唯一负责处理客户端写请求的节点;也可以处理客户端读请求;同时负责日志复制工作
Candidate【候选人】:Leader 选举的候选人,其可能会成为 Leader
Follower【从】:可以处理客户端读请求;负责同步来自于 Leader 的日志;当接收到其它Cadidate 的投票请求后可以进行投票;当发现 Leader 挂了,其会转变为 Candidate 发起Leader 选举
除了三种角色外,还有一个iterm,可以将其看为一个编号,在Leader选举中发挥作用.
leader选举流程:
(1)成为候选人
若 follower 在心跳超时范围内没有接收到来自于 leader 的心跳,则认为 leader 挂了。此时其首先会使其本地 term 增一。然后 follower 会完成以下步骤:
a、此时若接收到了其它 candidate 的投票请求,会根据以下两种情况来判断是否投票:
如果在我当前 term 内,且我的选票还没有投出去,则会投票给该节点。(发来投票请求候选人candidate 的节点 term 不能小于我的 term)
如果当前Follower节点接收到多个 candidate 的请求,当前节点将采取,先到先得的方式投票
b、由 follower 转变为 candidate,本地 term 加一之前尚未投票,则向自己投一票,然后向其它节点发出投票请求,然后等待响应。响应结果可能有三种情况:
收到过半选票,成为新的 leader。然后会将消息广播给所有其它节点,以告诉大家我是新的 Leader 了,其中就包含新的 term
接收到别的 candidate 发来的新 leader 通知,比较了新 leader 的 term 并不比的 term小,则自己转变为 follower
经过一段时间后,没有收到过半选票,也没有收到新 leader 通知,则重新发出选举
(2) 票数相同怎么处理
若在选举过程中出现了各个 candidate 票数相同的情况,是无法选举出 Leader 的。当出现了这种情况时,其采用了 randomized election timeouts 策略来解决这个问题。其会让这些candidate 重新发起选举,只不过发起时间不同:各个 candidate的选举发起时间是在一个给定范围内等待随机时长 timeout 之后开始的。timeout 较小的会先开始选举,一般情况下其会优先获取到过半选票成为新的leader。
四、Raft 算法下集群脑裂情况
Raft 集群存在脑裂问题。在多机房部署中,由于网络连接问题,很容易形成多个分区。而多分区的形成,很容易产生脑裂,从而导致数据不一致。由于三机房部署的容灾能力最强,所以生产环境下,三机房部署是最为常见的。下面以三机房部署为例进行分析,根据机房断网情况,可以分为五种情况:
(1)情况一:不确定
这种情况下,B 机房中的主机是感知不到 Leader 的存在的,所以 B 机房中的主机会发起新一轮的 Leader 选举。由于 B 机房与 C 机房是相连的,虽然 C 机房中的Follower 能够感知到 A 机房中的 Leader,但由于其接收到了更大 term 的投票请求,所以 C 机房的 Follower也就放弃了 A 机房中的 Leader,参与了新 Leader 的选举。
若新 Leader 出现在 B 机房,A 机房是感知不到新 Leader 的诞生的,其不会自动下课,所以会形成脑裂。但由于 A 机房 Leader 处理的写操作请求无法获取到过半响应,所以无法完成写操作。但 B 机房 Leader 的写操作处理是可以获取到过半响应的,所以可以完成写操作。故,A 机房与 B、C 机房中出现脑裂,且形成了数据的不一致。
若新 Leader 出现在 C 机房,A 机房中的 Leader 则会自动下课,所以不会形成脑裂。
(2)情况二:会脑裂
这种情况与情况一基本是一样的。
A、C 可以正常对外提供服务,但 B 无法选举出新的 Leader,无法提供服务,没有形成脑裂。
(4)情况四:不会脑裂
A、B、C 均可以对外提供服务,不受影响。
(5)情况五:不会脑裂
A 机房无法处理写操作请求,但可以对外提供读服务。B、C 机房由于失去了Leader,均会发起选举,但由于均无法获取过半支持,所以均无法选举出新的Leader。
五、Leader宕机的四种情况处理
client发送请求到Nacos Config集群,Leader会将请求同步到Follower,同步完成后,才会返回客户端成功,但是存在各种情况,但是总的来说就是只有全部同步完成才会返回客户端成功。
(1) 情况1:请求到达前Leader挂了
client 发送写操作请求到达 Leader 之前 Leader 就挂了。因为请求还没有到达集群,所以这个请求对于集群来说就没有存在过,对集群数据的一致性没有任何影响。Leader 挂了之后,会选举产生新的 Leader。由于 StaleLeader 并未向 client 发送成功处理响应,所以 client 会重新发送该写操作请求。
(2) 情况2:未开始同步数据前Leader挂了
client 发送写操作请求给 Leader,请求到达 Leader 后,Leader 还没有开始向Followers复制数据 Leader 就挂了。这时集群会选举产生新的 Leader,前任Leader 重启后会作为Follower 重新加入集群,并同步新 Leader 中的数据以保证数据一致性。之前接收到 client 的数据被丢弃。由于前任 Leader 并未向 client 发送成功处理响应,所以 client 会重新发送该写操作请求。
(3) 情况3:同步完部分后Leader挂了
client 发送写操作请求给 Leader,Leader 接收完数据后开始向 Follower 复制数据。在部分 Follower 复制完后 Leader 挂了(可能过半也可能不过半)。由于Leader 挂了,就会发起新的 Leader 选举。
若 Leader 产生于已经复制完日志的 Follower,其会继续将前面接收到的写操作请求完成,并向 client 进行响应。
若 Leader 产生于尚未复制日志的 Follower,那么原来已经复制过日志的Follower 则会将这个没有完成的日志放弃。由于 client 没有接收到响应,所以client 会重新发送该写操作请求。
(4) 情况4:apply通知发出后Leader挂了
client 发送写操作请求给 Leader,Leader 接收完数据后开始向 Follower 复制数据。Leader成功接收到过半 Follower 复制完毕的响应后,Leader 将日志写入到状态机。此时 Leader 向Follower 发送 apply 通知。在发送通知的同时,也会向 client发出响应。此时 leader 挂了。由于 前任 Leader 已经向 client 发送成功接收响应,且 apply 通知已经发出,说明这个写操作请求已经被 server 成功处理。
-----------------------------------------------------------
---------------------------------------------
朦胧的夜 留笔~~