一致性协议整理(总述)

       一致性协议分布式环境下,解决如何在多节保证数据的一致性。分布式理论中,CAP 理论是分布式的理论基础,2PC 是分布式事务简单实现。本章首先简单介绍 CAP 理论和 2PC,然后介绍一致性协议实现的主要组成,比如 Leader 选举、日志同步、健康检查、故障恢复、脑裂和快照等。至于具体的协议实现如 Raft、ZAB 等不在本章做具体说明,将会在后面的章节做具体介绍。

CAP

1.什么是数据一致性?

      如图1/2,当用户向 DB1 插入数据 a 后,在向用户返回响应前,确保了 DB1、DB2 和 DB3 都有了 a 这个数据。所以在得到响应之后,用户不管访问那个库,都能保证获得到相同的数据。

2.什么是网络分区?

如图3所示,DB3 与 DB1 和 DB2 无法连通时,就会出现网络分区,在 DB1 和 DB2 修改的数据无法同步的 DB3,同样 DB3 修改的数据也无法同步到 DB1 和 DB2,这就出现网络分区。而 CAP 理论就提供一种思路和方法,去解决这个问题。

3.CAP理论如何解释上述的矛盾(一致性和网络分区)?

C:Consistency 一致性(数据一致)。

A:Availability 可用性,用户请求能够在有限的时间内返回响应(访问任意服务)。

P:Partition tolerance 分区容错性(分布式系统内部的网络故障)。

        根据 CAP理论,一个系统无法同时满足 C、A 和 P。而在分布式系统中要么实现 CP,要么实现 AP,为什么这么说?

        (1)分布式至少2台的机器,机器之间必须通过网络通信,既然是网络,就可能出现网络故障,如图3的情况,所以分布式系统必定满足 P。

        (2)在满足 A 的情况下(AP),如果向 DB1 插入数据 b,DB1 同步 DB2, 但在网络故障的情况下,DB1 无法同步 DB3, 导致数据不一致。在满足 A 的情况下, DB3 依然可以访问,但 read b时,无法获取数据。但访问 DB1 和 DB2 可以,从而导致读数据的不一致。

        (3)在满足 C 的情况下(CP),如果向 DB1 插入数据,DB1 同步 DB2, 但在网络故障的情况下,DB1 无法同步 DB3, 导致数据不一致。在满足 C 的情况下,由于数据不一致,访问数据会返回 error。

两阶段提交(2PC) 

阶段一

事务询问:

       1. 协调者向所有的参与者发生事务内容,询问是否可以执行事务提交操作。并开始等待各参与者的响应。

执行事务:

        1.各参与者节点执行事务操作,并将 undo 和 redo 信息写入事务日志。

        2.各参与者向协调者反馈事务询问的响应(YES/NO)。

阶段二(执行事务提交)

如果所有参与者反馈都是 Yes,那就进行事务提交:

  1. 发送提交请求。
  2. 事务提交。

参与者接收到Commit请求之后,会正式执行事务提交操作,并在完成提交之后释放资源:

  1. 反馈事务提交结果(ack to 协调者)。
  2. 协调者完成事务。

阶段二(执行事务滚回)

如果有参与者反馈是NO 或等待超时 那就进行事务滚回:

  1. 发送滚回请求。
  2. 事务滚回。

参与者接收到Rollback请求之后,通过Undo 滚回事务,并在完成之后释放资源:

  1. 反馈事务滚回结果(ack to 协调者)。
  2. 协调者中断事务。 

一致性协议实现

Leader 选举

首先在一致性协议中,需要一个 Leader 来管理 Follower (新增、移除)、提案、健康检查、事务ID的唯一性,对外提供 API 等。

 Leader 当选的条件会由协议的不同而所差异,但主要包括两点:

        (1)当选的节点包含了最新最全的数据。

        (2)当选的节点必须得到一半以上节点的同意。

Leader 发起的条件主要包括:

        (1)Follower 在一定时间内没有收到 Leader 心跳包,认为 Leader 已宕机,发起新一轮选举。

        (2)Leader 主动放弃,指定新的Leader。

       (3)在 Leader 维护节点状态的记录中,活跃的节点数不超过一半,可能出现网络分区,自动放弃 Leader 状态。

日志同步

同步从数据量角度来说,主要分为全量同步和增量同步,不同的场景按不同的方式同步:

        (1)新节点加入已有的集群,Leader 需要将全量数据的快照发送给新节点,在发送快照之后,需要进行增量同步,直到两个节点数据完全一致。

        (2)有新提案,Leader 需要增量同步到其他 Follower。

        (3)故障恢复的 Follower 节点,需要根据 Leader 与该节点在数据的差异程度来决定,如果差异比较大,那么直接使用全量同步。如果差异在可接受范围,使用增量同步。

        (4)日志同步从节点的角度来看,可以分为:

方式

说明

提交效率

数据安全

全同步

必须等到消息同步到所有副本,才对客户端返回响应

最安全

半同步

只需要同步到特定副本或者指定副本数量就可以对客户端返回响应

是全同步和异步的折中

安全

异步

只要Leader接收,就算成功

不安全

日志的顺序

通过事务 ID 的递增保证日志顺序,每个提案都需要通过 Leader 进行提案,Leader 保证为每个提案赋予唯一且递增的事务 ID。由于 ID 具有唯一且递增的特性,Leader 和 Follower 都能通过 ID 来判断自己缺失那些数据和应该同步那些数据。

集群节点健康检查

健康检查目的是判断节点的活跃状态,同时可能也会通过健康检查同步一些基本信息。

健康检查的主要方式是定时向目标节点发送心跳包。比如

        (1)A 向 B 发送心跳包,B接收之后更新A的状态记录(活跃状态,上次心跳包时间)

        (2)B 向 A 返回心跳包响应,A 接收响应更新 B的状态记录。

至于到底是 Leader 发送给 Follower心跳包,还是 Follower 心跳包都可以,只不过如果是 Leader 向 Follower 发送心跳包,在 Follower 数量达到一定的情况下,Leader 可能会忙于发送心跳包,而损害 Leader 的性能,甚至导致 Leader 不可用。同样 Follower 发送心跳包,也是一样的。所以节点的数量是需要控制的。

快照

快照是一个节点在某个时刻数据的全量数据(持久化),目的是用于加快节点重启恢复数据的速度和 Leader 全量同步数据给 Follower(生成快照的速度依赖于不同的压缩算法和压缩等级)。

首先任何一个提案记录或者系统配置的改变都会记录到一个持久化的 log 日志中,如果系统在提交日志之后宕机,可以通过该日志进行恢复。

二是在提交记录达到一定阈值或者系统在一定的时间周期内,会触发 checkPoint 机制,将系统内的数据生成一份数据快照,并记录同步信息。这时候如果系统宕机重启之后可以通过快照快速恢复大量数据,然后根据同步信息,在 log 中找到快照之后的记录,进行重做。

我曾经有疑问,为什么有了持久化日志之后,还要有快照数据,宕机之后直接通过 log 恢复不就可以了?如今已经找到答案:

        (1)log 日志虽然是持久化信息,因为是顺序写入,所以速度很快。同时可以根据mmap技术,实现更高效的写入速度。所以 log 持久化,不会成为瓶颈。

        (2)log 中记录的是原始的提案信息,这提案信息要预提交、同步、提交、最终才会被系统运用。所以如果根据 log 进行恢复,在存在大量日志的时候,恢复过程将非常漫长。

        (3)快照保存的是已提交应用的数据。不需要经历上面的流程,可以直接加载到内存中。

故障恢复

故障恢复包括以下几种情况:

        (1)Leader故障,这时候需要经过选举过程,选举出新的Leader,同时同步到Follower。

        (2)Follower 故障,当 Follower 重新恢复,并加入集群,根据实际情况选择全量同步或者增量同步,保证 Follower 数据和 Leader 一致。

        (3)集群出现网络分区。

如果上图,由于网络原因,导致节点1/节点2/节点3 与 节点4/节点5 无法通讯,从而形成 A 和 B 两个网络。则可能出现几种情况(这里有个前提必须有一半以上的节点同意才能当选Leader)

      (1)Leader 节点在 A 网络,由于 A 网络节点数超过一半,Leader 仍然可以与一半以上的节点通信,集群仍然保持正常。但 B 网络由于节点数据少于一半,无法选举新 Leader,不可用。

       (2)Leader 节点不在 A 网络,由于 A 网络节点数超过一半,发起新一轮选举,选举出 Leader,从而保证 A 网络可以。B 网络不可用。

      (3)Leader 在 B 网络,由于B网络节点数量少于一半,Leader 放弃 Leader,B网络节点不可用。

脑裂

脑裂发生在一个曾经运行良好的环境中,但由于某些原因,导致部分网络无法连通,使得 Leader 节点无法与部分节点通信。

无法与 Leader 通信的节点,因为收不到 Leader 心跳包,导致选举计时器超时,触发新一轮选举/预选举。

这样会导致多 Leader 的情况,多 Leader 情况下,无法保证日志的唯一性以及一致性。

读写一致性

写只能通过 Leader 进行,并同步给所有 Follower,只有接收到指定数量的 Follower 确认之后 Leader 才发起提交,并通知所有 Follower,此时数据才能被读取。

读可以在任何一个节点读取数据,但当从 Follower 读取数据时,会将请求转发给 Leader,然后由Leader 返回数据给 Follower,再把数据返回给客户端。

那么问题就来了,为什么不能直接从 Follower 读取数据?其实原因是 Leader 提交数据的条件只是收到指定数量的 Follower 确认,但并不保证所有节点都收到和提交了数据。如果访问了没用同步数据的Follower,那么就会导致读取数据的不一致。

总结

本文首先介绍了 CAP 理论,并解释了为什么在分布式环境中只能保证 AP 或者 CP。然后介绍了一致性协议中,重要的组成部分已经其相关的作用,比如Leader 选举、日志同步、快照、健康检查等等。希望这些对读者去理解一致性协议有帮助。下一章,会介绍一致性协议的具体实现如Raft、ZAB。

参考

  1. 《ETCD技术内幕》
  2. 《从Paxos到ZooKeeper》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值