为什么需要一致性
1、数据不能存在单个节点上,否则可能出现单点故障。
2、如果用多节点,就需要保证数据的一致性
什么是一致性
CAP 理论
对于一个分布式系统,不能同时满足以下三点:
- 一致性(Consistency)
- 可用性(Availability)
- 分区容错性(Partition Tolerance)
一致性
我们知道ACID中事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行前后,数据库都必须处于一致性状态。也就是说,事务的执行结果必须是使数据库从一个一致性状态转变到另一个一致性状态。
和ACID中的一致性不同,分布式环境中的一致性是指数据在多个副本之间是否能够保持一致的特性。
分布式系统中,数据一般会存在不同节点的副本中,如果对第一个节点的数据成功进行了更新操作,而第二个节点上的数据却没有得到相应更新,这时候读取第二个节点的数据依然是更新前的数据,即脏数据,这就是分布式系统数据不一致的情况。 在分布式系统中,如果能够做到针对一个数据项的更新操作执行成功后,所有的用户都能读取到最新的值,那么这样的系统就被认为具有强一致性(或严格的一致性)。
可用性
可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果,如果超过了这个时间范围,那么系统就被认为是不可用的。
“有限的时间内”是在系统的运行指标,不同系统会有差别。例如搜索引擎通常在0.5秒内需要给出用户检索结果。
“返回结果”是可用性的另一个重要指标,它要求系统完成对用户请求的处理后,返回一个正常的响应结果,要明确的反映出对请求处理的成功或失败。如果返回的结果是系统错误,比如"OutOfMemory"等报错信息,则认为此时系统是不可用的。
分区容错性
一个分布式系统中,节点组成的网络本来应该是连通的。然而可能因为某些故障,使得有些节点之间不连通了,整个网络就分成了几块区域,而数据就散布在了这些不连通的区域中,这就叫分区。
当你一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分就访问不到这个数据了。这时分区就是无法容忍的。
提高分区容忍性的办法就是一个数据项复制到多个节点上,那么出现分区之后,这一数据项仍然能在其他区中读取,容忍性就提高了。然而,把数据复制到多个节点,就会带来一致性的问题,就是多个节点上面的数据可能是不一致的。要保证一致,每次写操作就都要等待全部节点写成功,而这等待又会带来可用性的问题。
总的来说就是,数据存在的节点越多,分区容忍性越高,但要复制更新的数据就越多,一致性就越难保证。为了保证一致性,更新所有节点数据所需要的时间就越长,可用性就会降低。
一致性模型
- 弱一致性
- 最终一致性 不一定要很快生效,过一段时间生效也可以
- DNS (Domain Name System)
- Gossip(Cassandra的通信协议)
- 最终一致性 不一定要很快生效,过一段时间生效也可以
- 强一致性
- 同步
- Paxos
- Raft(multi-paxos)
- ZAB(multi-paxos)
强一致性算法
为描述Paxos算法,Lesile Lamport虚拟了一个叫做Paxos的希腊岛屿,这个岛按照议会民主制的政治模式制定法律,但是没有人愿意将自己的全部时间和经理放在这种事情上。所以无论是议员,议长或者传递纸条的服务员都不承诺别人需要时一定会出现,也无法承诺批准决议或者传递消息的时间。
Paxos算法
- Basic Paxos
- Multi Paxos
- Fast Paxos
Basic Paxos
角色介绍:
Client:系统外部角色,请求发起者,像民众
Propser:接收Client请求,像集群提出提议(Propose)。并在冲突发生时,起到冲突调节的作用,像议员,提民众提出议案。
Accpetor(Voter):提议投票和接受者,只有在形成法定人数(quorum,一般为多数,大于1/2)时,提议才会最终被接受,像过会。
Learner:提议接受者,backup,备份,对集群一致性没什么影响。像记录员。
步骤、阶段
1、prepare: proposer提出一个天,编号为N,此N大于这个Proposer之前提出的提案编号。请求acceptors的quorum接受。
2、Promise:如果N大于多数acceptor之前接受的任提案编号,则接受,否则拒绝。
3、Accept:如果达到了多数派,Proposer会发出accept请求,此请求包含提案编号N,以及提案内容。
4、Accepted:如果此acceptor在此期间没有收到任何编号大于N的提案,则接受此提案内容,否则忽略。
基本流程:
部分节点失败,但达到了Quorums,若Acceptor故障,表决时能达到多数派也没问题
Proposer失败: 若Proposer故障,没关系,再从集群中选出Proposer即可
潜在问题:活锁(Liveness)或dueling ,假设系统有多个Proposer,他们不断向Acceptor发出提案,还没等到上一个提案达到多数派下一个提案又来了,就会导致Acceptor放弃当前提案转向处理下一个提案,于是所有提案都无法通过了,可以引入随机等待来解决此问题。
Basic Paxos存在的问题
- 难实现
- 效率低,需要两轮RPC
- 活锁
Multi Paxos
Multi Paxos 提出了一个新概念,Leader:唯一的propser,所有的请求都需要经过此Leader
基本流程:
- 若集群中没有Leader,则在集群中选出一个节点,并声明他为第M任Leader。
- 集群中的Acceptor只表决最新Leader发出的最新提案。
- 其他步骤与Basic Paxos相同
算法优化:
减少角色,进一步简化,Multi Paxos角色过多,对于计算机集群而言,可以将Proposer、Acceptor和Learner三者身份集中在一个节点上,此时只需要从集群中选出Proposer,其他节点就都是Acceptor和Learner。类似于Raft算法。
Raft算法
Paxos算法实现比较困难,Raft算法是对Paxos算法的简化和改进
将达成共识的问题划分成三个子问题:
- Leader Election 怎么进行leader选举
- Log Replication 怎么将log同步到其他节点上
- Safety 怎么保证操作一致
重定义角色:
- Leader
- Follower
- Candidate
动画演示:thesecretlivesofdata.com/raft/
Raft场景测试:raft.github.io/
ZAB算法
基本与raft相同,只是在一些名词的叫法上有些区别:如ZAB将某一个leader的周期成为epoch,而raft则成为term。
实现上有些许不同:如raft保证日志连续性时,心跳方向为leader to follower。ZAB则相反。
zookeeper使用ZAB实现。
建议大家看这个视频,以上基本是对这个视频的总结,视频中讲的很清楚