分布式一致性算法
分布式一致性通常指的是系统中的所有节点对某个状态或值达成一致的过程。它涵盖了更广泛的概念,包括数据复制、状态同步、故障恢复等,他们是为了保证值一致性的,特点是不依赖中心化协调者,通过多数派投票实现容错
分布式事务协议是指 2PC,3PC 这些,为了让所有节点要么全部提交,要么全部回滚,创造出来的。他们也是满足 CAP 思想的算法,也可以称作刚性事务。他们是为了处理跨节点事务原子性的,特点是必须存在协调者集中控制流程
# Paxos 算法
Paxos 算法是基于消息传递且具有高度容错特性的分布式一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一,其解决的问题就是在分布式系统中如何就某个值(决议)达成一致
paxos 它和 2PC、3PC 的区别是它实现的是最终一致性,即算法执行后,允许部分节点没有更新值的状态存在,以此它更适合去处理一些业务相关的数据,而 2PC 则偏向处理集群管理相关的功能
# 算法过程
简单来说就是将集群分为提案者、决策者和记录者,集群一起维护了一个单调递增的方案 ID,通过半数投票的方式,来界定方案中的日志是否需要记录。以下是具体算法流程
准备阶段:每个提案者在提出提案时都会首先获取到一个具有全局唯一性的、递增的提案编号 N,然后将该编号赋予其要提出的提案,在第一阶段是只将提案编号发送给所有的表决者
表决者在收到某提案后,会将该提案编号 N 记录在本地,每个表决者仅会通过编号大于自己本地增大编号的提案,在批准提案时表决者会将以前接受过的最大编号的提案作为响应反馈给 Proposer
执行阶段:如果提案者收到了超过半数的批准,那么此时提案者会给所有的参与者发送真正的提案,这个时候提案者会发送提案的内容和提案编号。如果从表决者处收到了比自己更新的提案,此时会发送更新的提案
表决者收到提案请求后会再次比较本身已经批准过的最大提案编号和该提案编号,如果该提案编号大于等于已经批准过的最大提案编号,那么就执行该提案(此时执行提案内容但不提交),随后将情况返回给提案者,如果不满足则不回应或者返回 NO
通知阶段:当提案者收到超过半数的 accept,那么它这个时候会向所有的参与者发送提案的提交请求让它们强制执行该提案;提案者如果没有收到超过半数的 accept,那么它将会将递增该提案的编号,然后重新进入准备阶段

# raft 算法
redis 的哨兵选举机制,使用了 raft 算法,其思想借鉴了 paxos,Raft 本来是一个用户管理日志一致性的协议。在大多数哨兵认定主机客观下线之后,就需要进行性的哨兵选举了
大致按照如下顺序:
- 每个做主观下线的 sentinel 节点向其他 sentinel 节点发送命令,要求将自己设置为领导者,并且投自己一票。Follower 会自增自己的 term 号并且转换状态为 Candidate,然后将这个投出去
- 接收到的 sentinel 可以同意或者拒绝
- 如果该 sentinel 节点发现自己的票数已经超过半数并且超过了 quorum,将自己为领导者的消息同步集群中所有机器
- 如果此过程选举出了多个领导者,那么将等待一段时重新进行选举,如果集群中只有两个哨兵,那么选举的流程将非常耗时。选出 Leader 后 Leader 会从从机中选举出合适的从机进行故障转移
这也是著名的半数选举机制。raft 他其实重点侧重于在一群机器中选择出一个老大,而且他最初的目的是管理日志一致性,即这个老大原本应该会受到请求,并且把请求作为日志条目加入到它的日志中,然后并行的向其他服务器发起请求以复制日志条目。当这条日志被复制到大多数服务器上,Leader 将这条日志应用到它的状态机并向客户端返回执行结果。redis 只借鉴了它前半部分,舍弃了后半部分
关于 raft 的最简单的总结:
- 1,主节点客观下线后,从节点进行投票
- 2,从节点会维护一个递增的提案 ID,如果本轮提案失败,ID 加1
- 3,接受到提案的节点,每轮提案只能投一次票(一般是投给第一次收到本轮提案的机器),并且只会投票给比自己所记录的提案 ID(节点投票后会记录提案 ID)更大的候选人。这么做是为了选举安全性,防止有一些网络延迟的机器成为 leader
- 4,收到超过半数同意票的机器成为 leader,并且发送终止投票命令
看 raft 效果:https://raft.github.io/
# ZAB 协议
ZooKeeper 在解决分布式数据一致性问题自己写了一个协议叫 ZAB,该协议可以根据 ZK 的特殊情况更好的支持崩溃恢复功能。ZAB 和 redis 中的 raft 很像
# 崩溃恢复模式
当新建一个集群或者 Leader 挂掉之后会进入该模式,流程如下:
开始时我们按一定顺序启动集群中的机器,被启动的机器会首先投票给自己,投票内容为服务器的 myid 和 ZXID(服务器保存的最大提案 id),然后将消息广播出去,所有机器在收到投票信息后会将投票信息与自己的作比较。首先它会比较 ZXID,ZXID 大的优先为 Leader,如果相同则比较 myid,myid 大的优先作为 Leader
执行以上过程直到某台机器的票数超过半数,该机器成为 Leader
# 崩溃恢复需要满足的要求
Zab 协议崩溃恢复要求满足以下两个要求:
- 1,确保已经被 Leader 提交的提案必须最终被所有的 Follower 服务器提交。为了满足这一点我们需要重试
- 2,确保丢弃已经被 Leader 提出的但是没有被提交的提案
# 消息广播模式
当集群中存在 Leader 时,自动进入消息广播模式,流程如下:
客户端发起一个写操作请求,从机收到请求后会将该请求发给主机
Leader 服务器将求转化为事务提案,同时为每个提案分配一个全局的 ID,Leader 服务器为每个 Followe 服务器分配一个单独的队列,然后将需要广播的提案依次放到队列中,并且根据 FIFO 策略进行消息发送
Follower 接收到提案后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后 Leader 反馈一个响应消息
Leader 接收到超过半数以上 Follower 的成功响应消息后,即认为消息发送成功,发送提交消息,自身也会完成事务提交
Leader 服务器与每一个 Follower 服务器之间都维护了一个单独的 FIFO 消息队列进行收发消息,使用队列消息可以保证数据传输的顺序性。请求处理的顺序不同就会导致数据的不同,从而产生数据不一致问题