在分布式系统中,为了保证数据的高可用,通常,我们会将数据保留多个副本(replica),这些副本会放置在不同的物理的机器上。为了对用户提供正确的增\删\改\差等语义,我们需要保证这些放置在不同物理机器上的副本是一致的。分布式一致性又分为强一致性和弱一致性:
弱一致性:
强一致性:
BASE全称:Basically Available(基本可用),Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写,来自 ebay 的架构师提出。
Base 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大型互联网分布式实践的总结,是基于 CAP 定理逐步演化而来的。其核心思想是:
虽然无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。
1.基本可用
基本可用是指:系统出现了不可预知的故障,但还是能用,相比较正常的系统而言:
2.软状态
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。例如MySQL读写分离的延时。
3.最终一致性
上面说软状态,然后不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性。从而达到数据的最终一致性。这个时间期限取决于网络延时,系统负载,数据复制方案设计等等因素。
为了解决这种分布式一致性问题,前人在性能和数据一致性的反反复复权衡过程中总结了许多典型的协议和算法。其中比较著名的有二阶段提交协议(Two Phase Commitment Protocol)、三阶段提交协议(Three Phase Commitment Protocol)和Paxos算法。
当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。
相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态(但是这种机制也会导致数据一致性问题)。
3PC 将阶段一 “提交事务请求” 分成了2部分,总共形成了3个部分:
无论是二阶段提交还是三阶段提交都无法彻底解决分布式的一致性问题。Google Chubby的作者Mike Burrows说过there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos。意即世上只有一种一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整版。
分布式系统对fault tolorence(容错)的一般解决方案是state machine replication。
state machine replication:复制状态机
一个分布式的复制状态机系统由多个复制单元组成,每个复制单元均是一个状态机,它的状态保存在一组状态变量中,状态机的变量只能通过外部命令来改变。简单理解的话,可以想象成是一组服务器,每个服务器是一个状态机,服务器的运行状态只能通过一行行的命令来改变。每一个状态机存储一个包含一系列指令的日志,严格按照顺序逐条执行日志中的指令,如果所有的状态机都能按照相同的日志执行指令,那么它们最终将达到相同的状态。因此,在复制状态机模型下,只要保证了操作日志的一致性,我们就能保证该分布式系统状态的一致性。
主从同步
主从同步复制:
问题在于当一个Slave节点失败时,Master节点会阻塞,导致整个集群不可用,虽然保证了一致性,但可用性却大大降低。
多数派
每次写入保证写入大于N/2个节点,每次读保证从大于N/2个节点读。
问题在于在并发环境下,无法保证系统的正确性,执行顺序很重要。
Paxos的作者Leslie Lamport早在2001年就写过一篇Paxos Made Simple的论文,来尽可能的简化Paxos的描述。Lamport虚拟了一个叫做Paxos的希腊城邦,这个岛按照议会民主制的政治模式制定法律,但是没有人愿意将自己的全部时间放在这件事上。所以无论是议员,议长或者传递字条的服务员都不能承诺别人需要时一定会出现,也无法承诺批准决议或者传递消息的时间(体现了网络的不可靠性)。
Basic Paxos角色:
执行过程:
参考:https://www.jianshu.com/p/ecc6168b33a7
在Basic Paxos协议中,有很多次的执行过程,每次执行过程产生一个单独的执行结果。每次执行过程都有很多轮次,每一轮都有2个阶段。
阶段1
阶段2
该流程如果失败,将提案编号增加后重试
问题:难以实现,效率低(要经过2轮RPC),可能会出现活锁。
在Basic Paxos协议中,每一次执行过程都需要经历Prepare->Promise->Accept->Accepted 这四个步骤,这样就会导致消息太多,从而影响分布式系统的性能。Multi Paxos提出了Leader的概念
如果Leader足够稳定的话,在接下来的执行中,phase 1的请求其实是可以被省略的。这里round number需要+1,表示已经进入下一轮了。
在Basic-Paxos中我们区分了很多角色,有Clients,Proposers, Acceptors and Learners。实际上Proposers, Acceptors and Learners可以合并成一个,我们把它统称为Server。下面是合并之后的序列图:
这种简化更加符合现实中多节点Server的构架。
Paxos 算法的描述偏学术化,缺失了很多细节,无法直接应用于工程领域。实际工程应用中的分布式算法大多是 Paxos 的变种,验证这些算法的正确性也成为了一个难题。Raft协议就是Paxos的简化,类似Multi Paxos。
Raft集群中每个进程只能担任其中一个角色:
正常运行的情况下,会有一个Leader,其他全为Follower,Follower只会响应Leader和Candidate的请求,而客户端的请求则全部由Leader处理,即使有客户端请求了一个Follower也会将请求重定向到Leader。Candidate代表候选人,出现在选举Leader阶段,选举成功后Candidate将会成为新的Leader。
Raft 将一致性问题分解为 3 个独立的子问题:
Election
:Leader 进程失效后能够自动选举出一个新的 LeaderReplication
:Leader 保证其他节点的日志与其保持一致Safety
:Leader 保证状态机执行指令的顺序与内容完全一致p.s. Redis中的sentinel模式使用的就是Raft协议,Raft在Redis内并没有用来实现一些分布式锁以及分布式事务,仅仅是用来做master宕机时的选主,可能后续的版本会逐渐支持。
更多可参考:https://zhuanlan.zhihu.com/p/91288179
ZAB协议全称:Zookeeper Atomic Broadcast(Zookeeper 原子广播协议)。
ZAB协议定义:ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复和原子广播协议。
Zookeeper是一个为分布式应用提供高效且可靠的分布式协调服务。在解决分布式一致性方面,Zookeeper并没有使用Paxos,而是采用了ZAB协议。
ZAB协议基本与Raft相同,都是Multi Paxos的衍生。ZAB与Raft在一些名词的叫法上有区别:如ZAB将某一个Leader的周期称为epoch,而Raft则称之为term。在实现上也有些许不同:Raft为了保证日志连续性,心跳方向为Leader至Follower,ZAB则相反。
消息广播模式:
ZAB协议的消息广播过程使用的是一个原子广播协议,类似一个2PC二阶段提交过程。
(1)Leader将客户端的request转化成一个Proposal(提议);
(2)Leader为每一个Follower准备了一个FIFO队列,并把Proposal发送到队列上;
(3)Leader若收到follower的半数以上ACK反馈;
(4)Leader向所有的follower发送commit。
崩溃恢复:
ZAB 定义了 2 个原则:
所以,ZAB 设计了下面这样一个选举算法:**能够确保提交已经被 Leader 提交的事务,同时丢弃已经被跳过的事务。**针对这个要求,如果让 Leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器编号(即 ZXID最大)的事务,那么就能够保证这个新选举出来的 Leader 一定具有所有已经提交的提案。
ZXID:在 ZAB 协议的事务编号 ZXID 设计中,ZXID 是一个 64 位的数字,其中低 32 位可以看作是一个简单的递增的计数器,针对客户端的每一个事务请求,Leader 都会产生一个新的事务 Proposal 并对该计数器进行 + 1 操作。而高 32 位则代表了 Leader 服务器上取出本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的 epoch 值,然后再对这个值加一。高 32 位代表了每代 Leader 的唯一性,低 32 代表了每代 Leader 中事务的唯一性。同时,也能让 Follwer 通过高 32 位识别不同的 Leader。简化了数据恢复流程。
基于这样的策略:当 Follower 链接上 Leader 之后,Leader 服务器会根据自己服务器上最后被提交的 ZXID 和 Follower 上的 ZXID 进行比对,比对结果要么回滚,要么和 Leader 同步。
其选举流程可参考:https://www.cnblogs.com/veblen/p/10992103.html