Nacos 中的算法解读

一、分布式系统基础理论
1个服务,单节点,服务多了之后就是分布式的系统:
一主二从架构:分布式架构【数据的一致性问题】
redis --> Nginx --> 服务
服务【2K QPS】 * 5 ==集群 【1w QPS】
1.1 .1 CAP理论
数据库主从集群,分布式事务,系统支持集群!
1、什么是CAP?
CAP 是 Consistency、Availability、Partition tolerance 三个单词的缩写,分别表示一致性、可用性、分区容忍性。
一致性(C):分布式系统中多个主机之间是否能够保持数据一致的特性。即,当系统数据发生更 新操作后,各个主机中的数据仍然处于一致的状态。
可用性(A):系统提供的服务必须一直处于可用的状态,即对于用户的每一个请求,系统总是可 以在有限的时间内对用户做出响应。
分区-容忍性(P):分布式系统在遇到任何网络分区故障时,仍能够保证对外提供满足一致性和可 用性的服务。
对于分布式系统,网络环境相对是不可控的,出现网络分区是不可避免的,因此系统必须具备分区容错 性。但其并不能同时保证一致性与可用性。
CAP 原则对于一个分布式系统来说,只可能满足两项,即要么 CP 强一致性,要么 AP强可用性。
业务场景:商品信息管理的执行流程:

Nacos 中的算法解读_第1张图片

商品服务请求主库写入商品信息(添加、修改或删除商品) 主库向商品服务响应写入成功
商品服务请求从库读取商品信息

2、CAP的三种组合方式
上边商品管理的例子是否同时具备 CAP 呢?
在所有分布式系统场景中不会同时具备 CAP 三个特性!因为在具备了P的前提下C和A是不能共存的

如果要保住C【一致性】 则在数据同步的时候为防止向从数据库查询不一致的数据则需要将从数据库数据锁定,待同步完成后解锁,这样做势必牺牲可用性。如果要保住 A 【可用性】则不管任何时候都可以向从数据查询数据,则不会响应超时或返回错误信息。这样就不能上锁,不上锁势必影响一致性。通过 分析发现,在满足P【分区容错性】的前提下 C 和 A 存在矛盾性!
基于上述分析:所以生产中对分布式系统处理时,要根据需求来确定满足 CAP 的哪两个方面:要么
AP,要么CP。
AP:
放弃一致性,追求分区容忍性和可用性。这是很多分布式系统设计时的选择,例如Eureka
例如:上边的商品管理,完全可以实现 AP,前提是只要用户可以接受所查询到的数据在一定时间内不是最新的即可。
注:通常实现 AP 都会保证最终一致性,接下来讲的 BASE 理论就是根据 AP 来扩展的

CP:
放弃可用性,追求一致性和分区容错性。例如zookeeper 、跨行转账【一次转账请求要等待双方银行系统都完成整个事务才算完成,所以每次操作响应时间很长】。
CA【x】
放弃分区容忍性,即不进行分区,不考虑由于网络不通或结点挂掉的问题,则可以实现一致性和可用 性。
Nacos 中的算法解读_第2张图片

1.2 .2 BASE 理论
如果选择了AP,保证了可用性和分区容忍性,那么一致性就不重要吗?显然不是,所以说通常实现 AP
都会保证最终一致性,接下来讲 BASE 理论。首先我们来区分一下强一致性和最终一致性!

什么是强一致性和最终一致性?
数据写入分为三个阶段:开始,写入过程中,结束
强一致性:开始过程中和结束都必须保证数据的读取是一致性的!
最终一致性:开始和写入过程中,读取可以不是一致性的,但是最终数据最终保持一致!
Base 理论介绍
BASE 是 Basically Available(基本可用)、 Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的简写。
BASE 理论是 CAP 定理对于一致性与可用性权衡的结果。BASE 理论的核心思想是:即使无法做到强一致性,但每个系统都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。而且满足基 本可用条件,及存在软状态的可能性。

1、基本可用Basically Available
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。响应时间的损失、功能上 的损失
2、软状态 Soft state
软状态,是指允许系统数据存在的中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即 允许系统主机间进行数据同步的过程存在一定延时。软状态,其实就是一种灰度状态,过渡状态。
3、最终一致性Eventually consistent
最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状 态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强 一致性。
二 、Nacos Discovery一致性算法
目标 1. 什么是共识?数据的最终一致性?CAP是什么? 目标 2. Raft 算法:角色及Leader选举机制
目标 3. Raft 算法:日志复制机制
目标 4. Raft 算法:理解Raft如何解决集群潜在问题:1.数据的最终一致性,2.脑裂问题
2.1 .1 背景介绍
2.1.1 Nacos Discovery集群如何保证数据最终一致性?
Nacos采用了Raft算法【CP】保证数据强一致性。
当然不只是Raft,还有阿里巴巴的自己的Distro算法【AP】还有未来将会引入的Paxos算法!

Nacos Discovery 集群为了保证集群中数据的强一致性,其采用了 Raft 算法。这是一种通过对日志进行管理来达到一致性的算法。Raft 通过选举 Leader 并由 Leader 节点负责管理日志复制来实现各个节点间数据的一致性。
2.1.2 什么是Raft算法?
Raft算法是一种非常易于理解的分布式共识算法。Raft算法可以保障分布式系统数据的强一致性,解决分布式容错系统的共识问题。在容错性与性能表现方面等同于老牌的复杂的Paxos共识算法。
参考文件:RaftAlgorithm.pdf
2.1.3 什么是共识?
共识是分布式容错系统的基本问题。共识解决的是多个服务节点对数据达成一致的问题。
Raft 算法动画演示:http://thesecretlivesofdata.com/raft/
Raft 算法动画演示:https://raft.github.io/raftscope/index.html

2.1.4 Nacos Discovery是AP的?
Nacos默认是AP的,手动切换为CP!
Eureka 是 AP 的,Zookeeper 是 CP 的。默认情况下,Nacos Discovery 集群是 AP 的。但其也支持 CP
模式,需要进行转换。若要转换为 CP 的,可以提交如下 PUT 请求,完成 AP 到 CP 的转换。
http://localhost:8848/nacos/v1/ns/operator/switches?entry=ServerMode&value=CP
Nacos 中的算法解读_第3张图片

2.2 .2 Raft算法详解01:角色、任期及角色转变
注意:主节点有写入数据的权限。对系统的所有更改,都需要经过Leader节点。从节点没有权限,从节点只有读取权限!

在 Raft 中,节点有三种角色:
Leader【主】:唯一负责处理客户端写请求的节点;也可以处理客户端读请求;同时负责日志
【数据同步】复制工作
注意:只有主节点才拥有写入数据的权限!但是所有节点都可以读!
Candidate【候选人】:Leader 选举的候选人,其可能会成为 Leader
Follower【从】:可以处理客户端读请求;负责同步来自于 Leader 的日志;当接收到其它Cadidate 的投票请求后可以进行投票;当发现 Leader 挂了,其会转变为 Candidate 发起Leader 选举
Term:【任期/年号】什么是Term呢?

Nacos 中的算法解读_第4张图片

2.3 .3 Raft算法详解02:leader选举流程
超时timeout,收不到主节点心跳的时间【150ms-300ms】
Nacos 中的算法解读_第5张图片

(1) 成为候选人
若 follower 在心跳超时范围内没有接收到来自于 leader 的心跳,则认为 leader 挂了。此时其首先会使其本地 term 增一。然后 follower 会完成以下3个步骤:

  1. 此时若接收到了其它 candidate 的投票请求,则会将选票投给这个 candidate。如果没有,则自己由 follower 转变为 candidate,本地 term 加一
  2. 若之前尚未投票,则向自己投一票
  3. 向其它节点发出投票请求,然后等待响应
    (2) follower如何投票
    follower 在接收到投票请求后,会根据以下两种情况来判断是否投票:
    如果在我当前 term 内,且我的选票还没有投出去,则会投票给该节点。发来投票请求候选人candidate 的节点 term 不能小于我的 term
    如果当前Follower节点接收到多个 candidate 的请求,当前节点将采取,先到先得的方式投票
    (3) 等待响应
    当一个 Candidate 发出投票请求后,会等待其它节点的响应结果。响应结果可能有三种情况:
  4. 收到过半选票【有可能】,成为新的 leader。然后会将消息广播给所有其它节点,以告诉大家我是新的 Leader 了,其中就包含新的 term。
  5. 接收到别的 candidate 发来的新 leader 通知,比较了新 leader 的 term 并不比我的 term小,则自己转变为 follower
  6. 经过一段时间后,没有收到过半选票,也没有收到新 leader 通知,则重新发出选举

(4) 票数相同怎么处理
若在选举过程中出现了各个 candidate 票数相同的情况,是无法选举出 Leader 的。当出现了这种情况时,则会进行新一轮的投票,投票采用了 randomized election timeouts 策略来解决这个问题。其会让这些candidate 重新发起选举,只不过发起时间不同:各个 candidate 的选举发起时间是在一个给定范围内等待随机时长 timeout 之后开始的。
timeout 较小的会先开始选举,一般情况下其会优先获取到过半选票成为新的 leader。

2.4 .4 Raft算法详解03:脑裂
什么是脑裂?
在一个高可用系统中,当联系着的节点断开联系时,本来为一个整体的系统,分裂成两个独立节点,两 个节点开始争抢共享资源造成系统混乱、数据损坏的现象,成为“脑裂”。也称为网络分区。
Raft 集群存在脑裂问题。在多机房部署中,由于网络连接问题,很容易形成多个分区。而多分区的形成,很容易产生脑裂,从而导致数据不一致。由于三机房部署的容灾能力最强,所以生产环境下,三机 房部署是最为常见的。下面以三机房三节点部署为例进行分析,根据机房断网情况,可以分为五种情 况:
(1) 情况一:不会脑裂
Nacos 中的算法解读_第6张图片

C节点是B主节点的从节点。
C节点不是A主节点的从节点。
这种情况下,B 机房中的主机是感知不到 Leader 的存在的,所以 B 机房中的主机会发起新一轮的Leader 选举。由于 B 机房与 C 机房是相连的,虽然 C 机房中的 Follower 能够感知到 A 机房中的Leader,但由于其接收到了更大 term 的投票请求,所以 C 机房的 Follower也就放弃了 A 机房中的Leader,参与了新 Leader 的选举。

若新 Leader 出现在 B 机房,A 机房虽然感知不到新 Leader 的诞生的,但是A机房会通过C节点的Ack得知更高Term的B节点Leader,所以会主动下课。
当B机房被选举为新leader后,A机房会自动转为follower。之后A机房又无法通信到主节点(B),又会 发起新的选举,A又成为新的主节点,循环往复
(2) 情况二:会脑裂
Nacos 中的算法解读_第7张图片

这种情况与情况一基本是一样的。
(3) 情况三:不会脑裂
Nacos 中的算法解读_第8张图片

A、C 可以正常对外提供服务,但 B 无法选举出新的 Leader,无法提供服务,没有形成脑裂。
(4) 情况四:不会脑裂

Nacos 中的算法解读_第9张图片

A、B、C 均可以对外提供服务,不受影响。
(5) 情况五:不会脑裂
Nacos 中的算法解读_第10张图片

A 机房无法处理写操作请求,但可以对外提供读服务。B、C 机房由于失去了 Leader,均会发起选举, 但由于均无法获取过半支持,所以均无法选举出新的 Leader。
脑裂了数据就会不一致吗?Raft如何应对脑裂?
https://raft.github.io/raftscope/index.html
2.5 Raft算法详解04:主节点宕机如何保证数据最终一致性?
Nacos 中的算法解读_第11张图片

(1) 情况1:请求到达前Leader挂了
client 发送写操作请求到达 Leader 之前 Leader 就挂了。
因为请求还没有到达集群,所以这个请求对于集群来说就没有存在过,对集群数据的一致性没有任何影 响。Leader 挂了之后,会选举产生新的 Leader。由于挂了的Leader 并未向 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 成功处理。这里有问题了,如何保证数据不会成为脏数据呢?两个原则
领导人完全原则(Leader Completeness):如果一个日志条目在一个给定任期内被提交,那么这个条目一定会出现在所有任期号更大的领导人中。领导人完全原则(Leader Completeness Property)保证了领导人一定拥有所有已经被提交的日志条目,但是在它任期开始的时候,它可能不知道哪些是已经被 提交的。为了知道这些信息,它需要在它的任期里提交一条日志条目。
总结:Leader宕机后,Raft选举算法会保证下一个leader一定包含所有已经提交的日志,除非选举不 出leader(大多数节点都宕机的情况)。

https://raft.github.io/raftscope/index.html
三 、Nacos Discovery源码解析

Nacos 中的算法解读_第12张图片
Nacos架构图:
Nacos 中的算法解读_第13张图片

3.1 .1 Nacos Client源码分析:服务注册与心跳
3.1.1 源码分析
目标1:理解Client注册服务流程
Nacos 客户端的注册,最终是通过 Nacos 自定义的 RestTemplate 发出的 POST 请求提交给
Nacos Server
目标2:理解Client心跳定时任务代码流程
Nacos Client 的注册最终是通过 Nacos 自定义的 HttpClient 发出的 PUT 请求提交给Nacos Server
的。
3.1.2 Nacos与Spring Cloud整合
1、Nacos与Spring Cloud整合–依赖项
无论是哪种组件作注册中心,若其要连接到 Spring Cloud 中,都需要遵循其规范。所以,我们在分析Nacos 与 Spring Cloud 整合之前,就需要了解这个规范。了解了这个规范,就可以搞清楚Nacos如何与SpringCloud整合。也可以明白Nacos的客户端如何启动。

Nacos 中的算法解读_第14张图片

A、spring-cloud-commons依赖
Spring Cloud 的 spring cloud commons 依赖中的自动配置类
AutoServiceRegistrationAutoConfiguration 完成了服务注册的自动配置。
Nacos 中的算法解读_第15张图片

第 35-36 行表示注入 AutoServiceRegistration。不过,这里有个问题:这个实例是在哪里生成的呢?
B、spring-cloud-starter-alibaba-nacos-discovery依赖
我们要使用 Nacos Discovery,就需要导入 spring-cloud-starter-alibaba-nacos-discovery 依赖。而该依赖又依赖于 spring-cloud-commons 依赖。
spring-cloud-starter-alibaba-nacos-discovery 依赖加载了一个自动配置类
NacosServiceRegistryAutoConfiguration。
Nacos 中的算法解读_第16张图片

发现这个配置类中创建了 NacosAutoServiceRegistration 实例。

Nacos 中的算法解读_第17张图片

NacosAutoServiceRegistration类的接口为AutoServiceRegistration,所以在这里将AutoServiceRegistration接口实现类对象注入到spring容器。
Nacos 中的算法解读_第18张图片

2、Nacos与Spring Cloud整合–监听器触发
Nacos 中的算法解读_第19张图片

NacosAutoServiceRegistration 类继承自 bstractAutoServiceRegistration 类。
Nacos 中的算法解读_第20张图片

打开 AbstractAutoServiceRegistration 类发现其实现了 Spring 的 ApplicationListener 接口,即实现了该接口的 onApplicationEvent()方法。
Nacos 中的算法解读_第21张图片
结 论:整合Nacos与SpringCloud整合的关键在于,通过starter依赖注入相关对象。
N acosAutoServiceRegistration 实现了监听器接口的监听方法。这个方法在SpringBoot项目启动后执行。
3、Nacos与Spring Cloud整合–启动NacosClient的入口
启动NacosClient的入口onApplicationEvent() 方法

Nacos 中的算法解读_第22张图片
A、bind()
当 Tomcat 启动后会触发 onApplicationEvent()方法的执行。onApplicationEvent()方法中首先调用bind()方法
Nacos 中的算法解读_第23张图片
Nacos 中的算法解读_第24张图片
Nacos 中的算法解读_第25张图片

B、register()
Nacos 中的算法解读_第26张图片
Nacos 中的算法解读_第27张图片

C、register(Registration)
Nacos 中的算法解读_第28张图片

D、registerInstance()
Nacos 中的算法解读_第29张图片

第 198 行是 Client 向 Server 发送心跳。第 200 行是 Client 向 Server 的注册。Nacos Client 实例分为两种:

临时实例【emphemeral is true】:默认类型,其会被注册到 Nacos Server 的内存。
持久实例【emphemeral is false】:其会被注册到 Nacos Server 的内存,并被持久化到磁盘。
3.1.3 注册服务源码流程
Nacos 中的算法解读_第30张图片

A、registerInstance()

Nacos 中的算法解读_第31张图片

Nacos 中的算法解读_第32张图片
在这里插入图片描述
Nacos 中的算法解读_第33张图片

B、reqApi()

Nacos 中的算法解读_第34张图片

Nacos 中的算法解读_第35张图片

这里对 Nacos Server 的选取采用的是随机策略。
Nacos 中的算法解读_第36张图片

C、callServer()

Nacos 中的算法解读_第37张图片
Nacos 中的算法解读_第38张图片

D、exchangeForm()

Nacos 中的算法解读_第39张图片
Nacos 中的算法解读_第40张图片

Nacos 中的算法解读_第41张图片
Nacos 中的算法解读_第42张图片

结 论:Nacos 客户端的注册,最终是通过 Nacos 自定义的 RestTemplate 发出的 POST 请求提交给 Nacos Server
3.1.4 心跳定时任务源码流程
心跳定时任务是在上一次心跳执行完毕执行下一次心跳
Nacos 中的算法解读_第43张图片
Nacos 中的算法解读_第44张图片
Nacos 中的算法解读_第45张图片

Nacos 中的算法解读_第46张图片

Nacos 中的算法解读_第47张图片

心跳发送源代码,最终还是调用了reqApi()。注意,reqApi()是Client调用Server的公共方法。这里是Nacos自己封装的。

Nacos 中的算法解读_第48张图片
Nacos 中的算法解读_第49张图片

Nacos 中的算法解读_第50张图片
Nacos 中的算法解读_第51张图片
Nacos 中的算法解读_第52张图片

3.2 .2 Nacos Server源码剖析
目标1:理解Server处理注册请求的流程目标2:理解Server中一致性协议的实现
3.2.1 背景知识铺垫:
Nacos整体架构图:
Nacos 中的算法解读_第53张图片

Nacos逻辑架构大图:

Nacos 中的算法解读_第54张图片

服务管理:实现服务CRUD,域名CRUD,服务健康状态检查,服务权重管理等功能一致性协议:解决不同数据,不同一致性要求情况下,不同一致性机制 OpenAPI:暴露标准Rest风格HTTP接口,简单易用,方便多语言集成 Console:易用控制台,做服务管理、配置管理等操作
3.2.2 Nacos Server 源码中的一些重要类:
在分析 Nacos Server 源码之前,首先需要搭建源码分析环境,其次需要了解一些重要的类、接口,这样才能更好的理解Nacos Sever 对 Client 的处理原理与过程。
Nacos系统设计:领域模型服务分级存储模型:

Nacos 中的算法解读_第55张图片

A、Service类在 Nacos 客户端的一个微服务名称定义的微服务,在 Nacos 服务端是以 Service 实例的形式出现的。
B、Cluster类隶属于某一 Service 的 Instance 集群。
C、Instance类注册到 Nacos 中的具体服务实例。
D、InstanceController控制器
在 Nacos 源码的 naming 模块下的 com.alibaba.nacos.naming.controllers 包下定义了很多的控制器类。其中 InstanceController 用于处理服务实例的心跳、注册等请求。
E、ServiceManager类Nacos 中所有 service 的核心管理者。
F、ConsistencyService接口
该实例用于提供 Nacos 集群节点间的数据同步服务。
3.2.3 Server处理注册请求

Nacos 中的算法解读_第56张图片

在 Nacos 源码的 naming 模块下的 om.alibaba.nacos.naming.controllers 包下的控制器类中的nstanceController 用于处理服务实例的心跳、注册等请求。笔记中仅仅给出这个请求处理开始分析了方法,详细解析,请查看添加了注释的源码。
Nacos 中的算法解读_第57张图片

你可能感兴趣的:(算法篇,Nacos)