迷谈分布式一致性
这篇文章的标题我也不知道是不是题文相关,依照分布式一致性和Zab协议这两个关键字搜索看了好多篇文章,但是依然很迷糊。
有些文章甚至研究的是区块链里的分布式一致性算法(大佬,告辞)。
所以叫迷谈,但尽量不胡谈,起码是参考过别的文章,不是瞎掰。
分布一致性类型
- 强一致性:写入什么数据读出来就是什么数据。任何时候读出来的数据都是最新的
- 弱一致性:不承诺能立即读到新值,也不承诺多久之后能读到新值,但会尽量确保在一个时间级别(例如秒级)能读到新值
- 最终一致性:是弱一致性的一种特例,保证在一定时间内能读到新值
CAP理论
分布式系统只能最多同时满足可用性、一致性和分区容错性的其中两个。
由于分布式系统的分区特性是无法避免的,所以实际上分布式系统只能在可用性和一致性之间做妥协。
- 一致性(Consistency):数据在任何时候都是一致的(强一致性)
- 可用性(Availability):服务一直处于可用状态,在有限时间内返回结果(强可用性)
- 分区容错性(Partition tolerance):当系统出现网络分区故障时,仍能对外提供满足一致性和可用性的服务
BASE理论
BASE理论的核心想法是,即使做不到强一致性,也至少要保证最终一致性,允许可用性只要求基本可用以加强一致性。
- 基本可用(Basically Available):系统出现故障时允许丢失部分可用性,例如增加响应时间,服务降级等
- 软状态(Soft state):允许系统数据存在中间状态,即系统的不同节点之间的数据同步存在延迟
- 最终一致性(Eventually consistent):系统的所有节点经过一段时间的同步之后都会达到一致
两阶段提交
两阶段提交以及升级版的三阶段提交都是只是缓解了数据不一致的问题,并没有完全解决问题。
看步骤感觉跟分布式事务的两阶段提交和TCC(Try Confirm
Cancel)有点像,不知道是不是同一个东西。
- 将数据发送到全部节点,等待节点确认
- 如果全部节点都确认了,则向全部节点发送提交,否则返回失败
Paxos协议
网上说好难理解,看过的那几篇文章都没展开介绍,所以就懒得写了。
Raft协议
Raft里,节点有三种状态,且同时只会处于其中一种状态:
- 从节点:初始时节点都是从节点状态
- 候选节点:当从节点收不到主节点的心跳,从节点会变为候选节点
- 主节点:候选节点会让其他节点给自己投票,获取过半数票节点变为主节点。
读操作全部节点处理,写操作主节点处理。
写同步我看文章理解是类似二段提交(那这样子怎么就解决了呢?)
ZAB协议
ZAB全称Zookeeper Atomic
Broadcast(zookeeper原子广播),据说参考了Paxos,是zookeeper里的分布式一致性的实现。
虽然我不晓得Paxos是啥样,但是有其中一篇文章说ZAB是简化版的两阶段提交,我看来确实有点像两阶段提交,还是说其实都像。
zookeeper的节点除了主节点和从节点以外还有观察节点,但是观察节点不参与投票,所以Zab协议并没有观察节点的什么事。
zookeeper的读操作可以由全部节点直接处理,而从节点和观察节点接受到写操作会转发给主节点处理。
ZAB协议包含两部分,分别是正常状态下的消息广播和异常状态下的崩溃恢复。
消息广播
- 主节点会将写请求提案(Proposal),并且每个提案都有一个递增的zxid(高32位表示年代,低32位自增)
- 主节点对每个从节点都会有一个队列用来存放、异步投递提案,提高性能
- 从节点收到提案后会把提案数据进行持久化,然后给主节点发送确认
- 主节点收到过半数从节点的确认后,就会向全部从节点发送提交,并且同时也会提交自己的提案,然后给客户端返回成功
- 从节点收到主节点的提交后,会提交自己的提案
上面有几个补充说明的问题:
- 为什么过半数就可以提交:因为只要过半数,就能确保至少有一个从节点是保存着全部的数据或者提案的,它将有机会在奔溃恢复中被选举为新的主节点
- 在从节点确认提案和主节点提交提案这两步有点像两阶段提交,从节点都没收到提交,主节点给客户端返回成功但自己挂了的情况,依然不理解怎么解决
奔溃恢复
当集群刚启动时,或者主节点失去与过半数从节点联系时,会进入奔溃恢复选举主节点
- 所有从节点一开始先投票给自己,把自己的投票结果发给其他节点
- 节点收到其他节点的投票结果,依据
epoch更大->zxid更大->myid更大
,决定是否要修改投票,要改的话则把新的投票发给其他节点 - 有节点获票过半数,当选主节点,会使结果偏向
epoch最大 && zxid最大 && myid最大
- 新的主节点会与其余从节点同步数据,直到同步完成才接受请求,对自己的年代加一
上面有几个补充说明的问题:
- 文章里都说:确保被主节点提交的提案必须最终被所有的从节点提交。
但是按这套逻辑实现不了呀,确保被过半数从节点确认/至少一个从节点提交的提案必须最终被所有的从节点提交倒是可以 - 文章里都说:确保丢弃被主节点提出的但是没有被提交的提案。没有看到有文章说明是怎么个丢弃法。
参考文章: