分布式一致性理论和Nacos应用

发布时间:2024年01月03日

分布式一致性理论

1. CAP理论

  • C consistency 一致性 分布式系统各节点数据强一致性
  • A availability 可用性 对外保持可用 不管数据是否一致
  • P partition tolerance 分区容错性(节点网络分区)

把所有的服务都放在一个网络分区,但是当网络出现故障时,整个系统都无法对外提供服务,那这还有什么意义呢?
分布式系统实现网络分区 必须实现分区容错性,剩下的就是 是选择一致性 还是可用性 也就是CP还是AP

为什么不能同时实现一致性和可用性?

网络分区AB网络通信失败的话
如果保持可用性 AB两个节点的数据无法同时更改数据,造成数据不一致
如果保持数据强一致性 AB网络不通,所以必须两个节点都不能更改数据,导致对外数据无法更改,节点不可用

优化
如果保证节点可用的情况下,先修改A的数据,网络恢复后更改B节点,达到数据最终一致性---->BASE理论

2. BASE理论

基本可用: 系统出现故障,但是还是能够对外提供服务,不能直接不可用
软状态: 允许各个节点数据不一致
最终一致性: 瞬时允许节点数据不一致,但是一定时间之后,各个节点数据一致

2.1 BASE理论

Base 是三个短语的简写,即基本可用(Basically Available)、软状态(Soft State)和最终一致性(Eventually Consistent)。
Base 理论的核心思想是最终一致性,即使无法做到强一致性(Strong Consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual Consistency)。

  • 基本可用比较好理解,就是不追求 CAP 中的「任何时候,读写都是成功的」,而是系统能够基本运行,一直提供服务。基本可用强调了分布式系统在出现不可预知故障的时候,允许损失部分可用性,相比正常的系统,可能是响应时间延长,或者是服务被降级。
  • 软状态可以对应 ACID 事务中的原子性,在 ACID 的事务中,实现的是强制一致性,要么全做要么不做,所有用户看到的数据一致。其中的原子性(Atomicity)要求多个节点的数据副本都是一致的,强调数据的一致性。
    原子性可以理解为一种“硬状态”,软状态则是允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
  • 数据不可能一直是软状态,必须在一个时间期限之后达到各个节点的一致性,在期限过后,应当保证所有副本保持数据一致性,也就是达到数据的最终一致性。

在系统设计中,最终一致性实现的时间取决于网络延时、系统负载、不同的存储选型、不同数据复制方案设计等因素。

2.2 BASE和CAP

Base 理论是在 CAP 上发展的,CAP 理论描述了分布式系统中数据一致性、可用性、分区容错性之间的制约关系,当你选择了其中的两个时,就不得不对剩下的一个做一定程度的牺牲。

Base 理论则是对 CAP 理论的实际应用,也就是在分区和副本存在的前提下,通过一定的系统设计方案,放弃强一致性,实现基本可用,这是大部分分布式系统的选择,比如 NoSQL 系统、微服务架构。在这个前提下,如何把基本可用做到最好,就是分布式工程师们追求的,在这个课程中,我们也会有专门的模块来讲解高可用。

除了 CAP 和 Base,上面还提到了 ACID 原理,ACID 是一种强一致性模型,强调原子性、一致性、隔离性和持久性,主要用于在数据库实现中。Base 理论面向的是高可用、可扩展的分布式系统,ACID 适合传统金融等业务,在实际场景中,不同业务对数据的一致性要求不一样,ACID 和 Base 理论往往会结合使用。

3. Nacos中的AP和CP

Nacos中目前是同时支持CP和AP的,具体看功能实现,不同的功能支持不同的理论
例如:

  • 临时服务注册,Nacos优先保持可用性,也就是AP
  • 永久服务注册,Nacos优先保持数据一致性。也就是CP

3.1、Nacos的AP实现

对于AP来说,Nacos使用的是阿里自研的Distro协议

在这个协议中,每个服务端节点是一个平等的状态,每个服务端节点正常情况下数据是一样的,每个服务端节点都可以接收来自客户端的读写请求

图片

当某个节点刚启动时,他会向集群中的某个节点发送请求,拉取所有的服务实例数据到自己的服务注册表中

图片

这样其它客户端就可以从这个服务节点中获取到服务实例数据了

当某个服务端节点接收到注册临时服务实例的请求,不仅仅会将这个服务实例存到自身的服务注册表,同时也会向其它所有服务节点发送请求,将这个服务数据同步到其它所有节点

图片

所以此时从任意一个节点都是可以获取到所有的服务实例数据的。

即使数据同步的过程发生异常,服务实例也成功注册到一个Nacos服务中,对外部而言,整个Nacos集群是可用的,也就达到了AP的效果

同时为了满足BASE理论,Nacos也有下面两种机制保证最终节点间数据最终是一致的:

  • 失败重试机制
  • 定时对比机制

失败重试机制是指当数据同步给其它节点失败时,会每隔3s重试一次,直到成功

定时对比机制就是指,每个Nacos服务节点会定时向所有的其它服务节点发送一些认证的请求
这个请求会告诉每个服务节点自己负责的服务实例的对应的版本号,这个版本号随着服务实例的变动就会变动。
如果其它服务节点的数据的版本号跟自己的对不上,那就说明其它服务节点的数据不是最新的。此时这个Nacos服务节点就会将自己负责的服务实例数据发给不是最新数据的节点,这样就保证了每个节点的数据是一样的了。

3.2、Nacos的CP实现

Nacos的CP实现是基于Raft算法来实现的

  • 在1.x版本早期,Nacos是自己手动实现Raft算法

  • 在2.x版本,Nacos移除了手动实现Raft算法,转而拥抱基于蚂蚁开源的JRaft框架

在Raft算法,每个节点主要有三个状态

  • Leader,负责所有的读写请求,一个集群只有一个
  • Follower,从节点,主要是负责复制Leader的数据,保证数据的一致性
  • Candidate,候选节点,最终会变成Leader或者Follower
    集群启动时都是节点Follower,经过一段时间会转换成Candidate状态,再经过一系列复杂的选择算法,选出一个Leader

图片

当有写请求时,如果请求的节点不是Leader节点时,会将请求转给Leader节点,由Leader节点处理写请求

  1. 比如,有个客户端连到的上图中的Nacos服务2节点,之后向Nacos服务2注册服务

  2. Nacos服务2接收到请求之后,会判断自己是不是Leader节点,发现自己不是

  3. 此时Nacos服务2就会向Leader节点发送请求,Leader节点接收到请求之后,会处理服务注册的过程

为什么说Raft是保证CP的呢?

主要是因为Raft在处理写的时候有一个判断过程

  • 首先,Leader在处理写请求时,不会直接数据应用到自己的系统,而是先向所有的Follower发送请求,让他们先处理这个请求
  • 当超过半数的Follower成功处理了这个写请求之后,Leader才会写数据,并返回给客户端请求处理成功
  • 如果超过一定时间未收到超过半数处理成功Follower的信号,此时Leader认为这次写数据是失败的,就不会处理写请求,直接返回给客户端请求失败
    所以,一旦发生故障,导致接收不到半数的Follower写成功的响应,整个集群就直接写失败,这就很符合CP的概念了。

不过这里还有一个小细节需要注意

Nacos在处理查询服务实例的请求直接时,并不会将请求转发给Leader节点处理,而是直接查当前Nacos服务实例的注册表

这其实就会引发一个问题

如果客户端查询的Follower节点没有及时处理Leader同步过来的写请求(过半响应的节点中不包括这个节点),此时在这个Follower其实是查不到最新的数据的,这就会导致数据的不一致

所以说,虽然Raft协议规定要求从Leader节点查最新的数据,但是Nacos至少在读服务实例数据时并没有遵守这个协议
当然对于其它的一些数据的读写请求有的还是遵守了这个协议。
JRaft对于读请求其实是做了很多优化的,其实从Follower节点通过一定的机制也是能够保证读到最新的数据

文章来源:https://blog.csdn.net/dumuzhouguohe/article/details/135357993
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。