分布式一致性算法

分布式一致性算法要解决哪些问题?

什么是分布式一致性?

简而言之,就是在分布式系统下要保证各个节点数据的一致性,也就是读和写两个操作都要保证一致性

在==单机情况==下解决一致性 涉及到并发操作或多线程环境下,可以采用事务或者加锁的方式来解决 但是在分布式系统下面,保证数据一致性的核心就是数据同步。但是在数据同步的过程中也会遇到一些问题:

  1. 服务的稳定性:各个节点(server)的状态不稳定,可能会宕机。
  2. 网络传输的稳定性:各个节点网络传输过程,网络发生抖动,同步请求会丢失。
  3. 网速问题:各个节点网络存在延迟,导致同步请求顺序发生改变

分布式一致性算法基于对CAP的遵循

CAP是 Consistency、Availability、Partition tolerance三个词语的缩写,分别表示一致性、可用性、分区容忍性。 是分布式系统处理数据一致性问题必须遵循的理论。 ①一致性 :对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。(要么数据正确,要么返回错误

可用性 :任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错。(不在乎数据是否正确,注重返回数据,但数据最终一致

分区容忍性 :由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。(对于多个节点,其中一个挂掉不影响其它节点服务

对于CAP的权衡:

在分布式系统中不可能同时满足CAP原理,只能满足其中的两个,但是为了保证分布式系统的健壮性,分区容忍性是必须要保证的,也就是说,在分布式系统中基于CAP原理,将保证分布式一致性分成两种,一种是强调强一致性==CA==,一种强调弱一致性(可用性)==AP==。 当选择了C(一致性)时,如果由于网络分区而无法保证特定信息是最新的,则系统将返回错误或超时。

当选择了A(可用性)时,系统将始终处理客户端的查询并尝试返回最新的可用的信息版本,即使由于网络分区而无法保证其是最新的。

对CAP举例

① 场景一: 有两个数据库,读写分离,主数据用来写数据,从数据用来读数据,某商品的价格是19999,双十一打折后9999,在双十一结束后,需要将主数据的9999改成19999,此时主数据已经修改,将去同步从数据库的数据,但是由于某种原因(服务器,网络)导致数据同步失败了,此时客户端去读从数据的价格还是9999元,这样就会导致出现损失,这种情况就要求强数据一致性。 ②场景二: 对于商品的评论信息,评论的数据展示不必要有及时性,这种情况如果是cp情况下,数据未同步,就会导致数据显示失败,评论就会加载失败。对于这种情况保证的是数据有,也就是可用性,用ap更合适。

分布式一致性算法

一般对于一致性算法基本都是讨论强一致性。 在了解分布式一致性算法在工程中实现之前,我们首先看看Mysql数据库主从复制的原理。这将有利于理解后面的Raft算法。

Binary Log(二进制日志):

  • 作用: Binary log 主要用于记录数据库中的所有修改操作,包括 INSERT、UPDATE、DELETE 等,以二进制格式存储。
  • 用途: 主要用于数据库恢复、点播恢复(point-in-time recovery)、以及主从复制。
  • 存储位置: Binary log 存储在主服务器上。

Relay Log(中继日志):

  • 作用: Relay log 用于存储从主服务器复制到从服务器的二进制日志事件。当从服务器从主服务器复制日志时,会先将主服务器的二进制日志内容保存到 Relay log 中。
  • 用途: 主从复制中从服务器用 Relay log 来保存主服务器上的二进制日志信息,以便从服务器能够执行相同的修改操作。
  • 存储位置: Relay log 存储在从服务器上。
  1. Master节点数据发生改变时,会将改动的sql写到Binary log日志文件中
  2. 对于Slave从节点而言,首先会开启一个I/O 线程用来读取主节点的Binary log日志文件
  3. 读取到数据以后,将数据写入到Relay log
  4. 此时Slave,专门开启SQL线程来读取Relay log中的数据,并执行

这样就保证了MySQL中各个节点的数据一致性。

Paxos的两阶段决议机制

讲Raft前,先讲Paxos算法。

  • Proposer: 提出提案 (Proposal)。Proposal信息包括提案编号 (Proposal ID) 和提议的值 (Value)。
  • Acceptor:参与决策,回应Proposers的提案。收到Proposal后可以接受提案,若Proposal获得多数Acceptors的接受,则称该Proposal被批准。
  • Learner:不参与决策,从Proposers/Acceptors学习最新达成一致的提案(Value)。

Paxos算法通过一个决议分为两个阶段(Learn阶段之前决议已经形成):

  1. 第一阶段:Prepare阶段。Proposer向Acceptors发出Prepare请求,Acceptors针对收到的Prepare请求进行Promise承诺。
  2. 第二阶段:Accept阶段。Proposer收到多数Acceptors承诺的Promise后,向Acceptors发出Propose请求,Acceptors针对收到的Propose请求进行Accept处理。
  3. 第三阶段:Learn阶段。Proposer在收到多数Acceptors的Accept之后,标志着本次Accept成功,决议形成,将形成的决议发送给所有Learners。

Paxos算法主要是基于多数决议保证数据的一致性的。如果多个节点的数据同步不一致,出现数据不一致的情况,按照少数服从多数的原则,保证数据一致性,这种思想也为后面的一致性算法比如Raft奠定了基础。

另外Paxos算法的效率比较低,每个决议需要两次请求(两个阶段)才能完成。但是在实际业务中,如果有大批量的消息需要决议,使用这种方式效率就很低了。

RAFT算法

算法流程:

  1. Client发送数据更改的请求,主节点Server收到请求后,放入Consensus Module (一致性模块)中
  2. Consensus Module 将请求给每个节点都发送一次,同时会将修改的请求放入Log日志文件
  3. Log日志文件将数据发送到State Machine中
  4. 最后返回给Clinet

选举机制

  • 多个Server共同选举产生一个Leader节点。负责响应客户端的请求。
  • Leader通过一致性决议,将客户端的指令发送到集群所有节点上。
  • 每个节点将客户端的指令以Entry的形式保存在自己的Log日志中,此时Entry是uncommitted状态。
  • 当有多数节点共同保存了entry之后,就可以执行Entry中的操作指令,提交到State Machine,此时Entry更新为committed状态。

领导者选举

Raft中节点的三种状态:从节点(node),候选节点(Candidate),主节点(Leader),所有的节点开始都是==从节点==,

此时如果没有节点收到主节点的信息,那么在从节点中就会有一个节点变成候选节点。 然后候选人向其他节点请求投票。 从节点在自身有票的情况下向候选节点投票,如果候选节点获得大多数节点(超过50%)的投票,则该候选节点成为主节点。 这个过程就是Raft的选举机制

选举机制

在 Raft 中,有两个超时设置来控制选举。选举超时是从节点等待成为候选节点的时间。选举超时随机时间为 150 毫秒到 300 毫秒之间。 选举时间结束从节点成为候选节点,开启新的任期 新的任期开始后,Term加一,并且候选节点向其余未成为候选节点的从节点发送投票请求,此时其余节点仍在等待选举超时。 从节点收到投票请求后,如果仍未投票,刷新选举超时时间,改变Term的值,并投票 一旦候选节点获得多数选票,它就会成为主节点。

成为主节点以后,向从节点追加消息,这些消息按==检测信号超时==指定的时间间隔发送。 丛节点收到消息后,会发送回信表示在工作状态。 这个选举任期将持续到从节点停止接收心跳并成为候选节点。依次按照上述过程重新选举新的候选节点和主节点。

两个候选节点

假如两个选举超时的时间相同,当选举超时时间结束以后,此时就会有两个候选节点产生,此时应该怎么解决呢? 如图,当A和D同时成为候选节点时,会同时向其余节点发送投票请求。 假如请求同时到达C和B 现在每个候选节点有 2 票,本届不能再获得选票。

此时,解决的办法就是,重新设置选举超时时间,直到新的候选节点产生。

Raft 日志复制

一旦我们选出了主节点,我们需要将对系统的所有更改复制到所有节点。这是通过每一次的心跳检测消息来完成的。 每个更改都放入节点日志中,但是该日志项当前++未提交++,因此不会更新节点的值。(红色表示未提交) 想要提交该数据,必须将该操纵同步到从节点的日志文件中 主节点向从节点发送同步信息,同时将结果返回给客户端,从节点收到主节点的同步信息,收到并返回信息告知主节点收到数据,此时主节点的日志文件的数据写入磁盘表示已经同步。 然后主节点告知从节点数据已提交,从节点提交数据,此时集群的节点中的数据已经是同步的状态。

网络分区

由于网络的延迟和网络的抖动,导致网络出现分区,此时由于选举机制会出现两个主节点,此时应该怎样保证数据一致性呢?

添加一个客户端来模拟 客户端2向NodeB发送set 3 的请求,此时主节点B,收到请求将请求写入日志文件中,此时向从节点A发送日志更新请求,A收到并回复, 此时B发现只有A回复,但是总共有五个节点,回复不到一般,不能保证更新。所以数据一直时未提交的状态。 此时于客户端1没有这种限制 当分区修复后,由于有两个主节点,怎样判断到底谁是最终的主节点呢? 此时就看主节点的Term的值,值越大表示有更高的选举期,而低的就会降级未从节点,并且数据会根据新的主节点进行更新

相关推荐
古希腊被code拿捏的神1 小时前
【Flutter】面试记录
flutter·面试·职场和发展
小飞悟2 小时前
那些年我们忽略的高频事件,正在拖垮你的页面
javascript·设计模式·面试
嘻嘻哈哈开森3 小时前
技术分享:深入了解 PlantUML
后端·面试·架构
爱学习的茄子3 小时前
JavaScript闭包实战:解析节流函数的精妙实现 🚀
前端·javascript·面试
Dgua3 小时前
🚀Promise 从入门到手写:核心方法实现全指南
前端·面试
Hilaku4 小时前
我为什么放弃了“大厂梦”,去了一家“小公司”?
前端·javascript·面试
然我4 小时前
React 事件机制:从代码到原理,彻底搞懂合成事件的核心逻辑
前端·react.js·面试
豆苗学前端5 小时前
从零开始教你如何使用 Vue 3 + TypeScript 实现一个现代化的液态玻璃效果(Glass Morphism)登录卡片
前端·vue.js·面试
阳火锅5 小时前
在生产环境下,你真的有考虑到使用数组方法的健壮性吗?
前端·javascript·面试
爱学习的茄子6 小时前
JavaScript闭包实战:防抖的优雅实现
前端·javascript·面试