分布式中一致性是很是重要的,分为弱一致性和强一致性。如今主流的一致性协议通常都选择的是弱一致性的特殊版本:最终一致性。下面就从分布式系统的基本原则讲起,再整理一些遵循这些原则的协议或者机制,争取通俗易懂。可是要真正实施起来把这些协议落地,可不是一片文章能说清楚的,有太多的细节,要本身去看论文呐(顺着维基百科找就好了)。java
CAP(Consistency
一致性,Availability
可用性,Partition tolerance
分区容错性)理论是当前分布式系统公认的理论,亦即一个分布式系统不可能同时知足这三个特性,只能三求其二。对于分布式系统,P
是基本要求,若是没有P
就不是分布式系统了,因此通常都是在知足P
的状况下,在C
和A
之间寻求平衡。mysql
ACID(Atomicity
原子性,Consistency
一致性,Isolation
隔离性,Durability
持久性)是事务的特色,具备强一致性,通常用于单机事务,分布式事务若采用这个原则会丧失必定的可用性,属于CP
系统。git
BASE(Basically Availabe
基本可用,Soft state
软状态,Eventually consistency
最终一致性)理论是对大规模的互联网分布式系统实践的总结,用弱一致性来换取可用性,不一样于ACID,属于AP
系统。github
2 Phase Commit,两阶段提交,系统有两个角色协调者和参与者,事务提交过程分为两阶段:web
提交事务请求(投票阶段)算法
undo
和redo
日志记录Yes
不然No
执行事务提交(执行阶段)sql
该协议能够视为强一致的算法,一般用来保证多份数据操做的原子性,也能够实现数据副本之间的一致性,实现简单,可是缺点也不少,好比单点故障(协调者挂了整个系统就无法对外服务,任一节点挂了事务就无法执行,没有容错机制)、阻塞(两个阶段都涉及同步等待阻塞,极大下降了吞吐量)、数据不一致(参与者回复Yes/No后若是由于网络缘由没有收到提交/中断请求,此时它就不知道该如何操做了,致使集群数据不一致)......数据库
2PC有些优化手段:超时判断机制,好比协调者发出事务请求后等待全部参与者反馈,若超过期间没有搜集完毕全部回复则能够多播消息取消本次事务;互询机制,参与者P回复yes后,等待协调者发起最终的commitabort,若是没收到那么能够询问其余参与者Q来决定自身下一步操做,避免一直阻塞(若是其余参与者全都是等待状态,那么P也只能一直阻塞了)。因此2PC的阻塞问题是没办法完全解决的。安全
固然,若是网络环境较好,该协议通常仍是能很好的工做的,2PC普遍应用于关系数据库的分布式事务处理,如mysql的内部与外部XA都是基于2PC的,通常想要把多个操做打包未原子操做也能够用2PC。网络
3 Phase Commit,三阶段提交,是二阶段提交的改进,系统也有两个角色协调者和参与者,事务提交过程分为三阶段:
事务询问(canCommit
)
执行事务预提交(preCommit
)
执行事务提交(doCommit
)
三阶段相对于两阶段的改善就是把准备阶段一分为二,亦即多了一个canCommit阶段,按我理解这样就相似于TCP的三步握手,多了一次确认,增大了事务执行成功的几率。并且3PC的协调者即便出了故障,参与者也能继续执行事务因此解决了2PC的阻塞问题,可是也可能所以致使集群数据不一致。
上面两个协议的协调者都须要人为设置而没法自动生成,是不完整的分布式协议,而Paxos 就是一个真正的完整的分布式算法。系统一共有几个角色:Proposer(提出提案)、Acceptor(参与决策)、Learner(不参与提案,只负责接收已肯定的提案,通常用于提升集群对外提供读服务的能力),实践中一个节点能够同时充当多个角色。提案选定过程也大概分为2阶段:
Prepare阶段
M
,向Acceptor某个超过半数的子集成员发送该编号的Prepare
请求Acceptor
收到M
编号的请求时,若M
大于该Acceptor
已经响应的全部Prepare
请求的编号中的最大编号N
,那么他就将N
反馈给Proposer
,同时承诺不会再批准任何编号小于M
的提案Accept阶段
[M,V]
提案的Accept请求给Acceptor,其中V
是收到的响应编号中编号的最大的提案值,若是响应中不包括任何提案值,那么他就是任意值[M,V]
的Accept请求只要改Acceptor还没有对大于M编号的提案作出过响应,他就经过这个提案Learn阶段(本阶段不属于选定提案的过程)
Paxos协议的容错性很好,只要有超过半数的节点可用,整个集群就能够本身进行Leader
选举,也能够对外服务,一般用来保证一份数据的多个副本之间的一致性,适用于构建一个分布式的一致性状态机。
Google的分布式锁服务Chubby就是用了Paxos协议,而开源的ZooKeeper使用的是Paxos
的变种ZAB协议。
Raft协议对标Paxos,容错性和性能都是一致的,可是Raft比Paxos更易理解和实施。系统分为几种角色: Leader(发出提案)、Follower(参与决策)、Candidate(Leader选举中的临时角色)。
刚开始全部节点都是Follower状态,而后进行Leader选举。成功后Leader接受全部客户端的请求,而后把日志entry发送给全部Follower,当收到过半的节点的回复(而不是所有节点)时就给客户端返回成功并把commitIndex设置为该entry的index,因此是知足最终一致性的。
Leader同时还会周期性地发送心跳给全部的Follower(会经过心跳同步提交的序号commitIndex),Follower收到后就保持Follower状态(并应用commitIndex及其以前对应的日志entry),若是Follower等待心跳超时了,则开始新的Leader选举:首先把当前term计数加1,本身成为Candidate,而后给本身投票并向其它结点发投票请求。直到如下三种状况:
在选举期间,Candidate可能收到来自其它自称为Leader的写请求,若是该Leader的term不小于Candidate的当前term,那么Candidate认可它是一个合法的Leader并回到Follower状态,不然拒绝请求。
若是出现两个Candidate得票同样多,则它们都没法获取超过半数投票,这种状况会持续到超时,而后进行新一轮的选举,这时同时的几率就很低了,那么首先发出投票请求的的Candidate就会获得大多数赞成,成为Leader。
在Raft协议出来以前,Paxos是分布式领域的事实标准,可是Raft的出现打破了这一个现状(raft做者也是这么想的,请看论文),Raft协议把Leader选举、日志复制、安全性等功能分离并模块化,使其更易理解和工程实现,未来发展怎样咱们拭目以待(挺看好)。
Raft协议目前被用于 cockrouchDB,TiKV等项目中,据我听的一些报告来看,一些大厂本身造的分布式数据库也在使用Raft协议。
Gossip协议与上述全部协议最大的区别就是它是去中心化的,上面全部的协议都有一个相似于Leader的角色来统筹安排事务的响应、提交与中断,可是Gossip协议中就没有Leader,每一个节点都是平等的。
每一个节点存放了一个key,value,version构成的列表,每隔必定的时间,节点都会主动挑选一个在线节点进行上图的过程(不在线的也会挑一个尝试),两个节点各自修改本身较为落后的数据,最终数据达成一致而且都较新。节点加入或退出都很容易。
去中心化的Gossip看起来很美好:没有单点故障,看似无上限的对外服务能力......原本随着Cassandra火了一把,可是如今Cassandra也被抛弃了,去中心化的架构貌似难以真正应用起来。归根到底我以为仍是由于去中心化自己管理太复杂,节点之间沟通成本高,最终一致等待时间较长...... 往更高处看,一个企业(甚至整个社会)不也是须要中心化的领导(或者制度)来管理吗,若是没有领导(或者制度)管理,你们就是人心涣散,难成大事啊。
事实上现代互联网架构只要把单点作得足够强大,再加上若干个强一致的热备,通常问题都不大。
首先看看这三个字母在分布式系统中的含义:
N:有多少份数据副本
W:一次成功的写操做至少有w份数据写入成功
R:一次成功的读操做至少有R份数据读取成功
NWR值的不一样组合会产生不一样的一致性效果,当W+R>N的时候,读取操做和写入操做成功的数据必定会有交集,这样就能够保证必定可以读取到最新版本的更新数据,数据的强一致性获得了保证,若是R+W<=N,则没法保证数据的强一致性,由于成功写和成功读集合可能不存在交集,这样读操做没法读取到最新的更新数值,也就没法保证数据的强一致性。
版本的新旧须要版本控制算法来判别,好比向量时钟。
固然R或者W不能太大,由于越大须要操做的副本越多,耗时越长。
Quorom
机制,是一种分布式系统中经常使用的,用来保证数据冗余和最终一致性的投票算法,主要思想来源于鸽巢原理。在有冗余数据的分布式存储系统当中,冗余数据对象会在不一样的机器之间存放多份拷贝。可是同一时刻一个数据对象的多份拷贝只能用于读或者用于写。
分布式系统中的每一份数据拷贝对象都被赋予一票。每个操做必需要得到最小的读票数(Vr)或者最小的写票数(Vw)才能读或者写。若是一个系统有V票(意味着一个数据对象有V份冗余拷贝),那么这最小读写票必须知足:
第一条规则保证了一个数据不会被同时读写。当一个写操做请求过来的时候,它必需要得到Vw个冗余拷贝的许可。而剩下的数量是V-Vw 不够Vr,所以不能再有读请求过来了。同理,当读请求已经得到了Vr个冗余拷贝的许可时,写请求就没法得到许可了。
第二条规则保证了数据的串行化修改。一份数据的冗余拷贝不可能同时被两个写请求修改。
Quorum机制其实就是NWR机制。
master给各个slave分配不一样的数据,每一个节点的数据都具备有效时间好比1小时,在lease时间内,客户端能够直接向slave请求数据,若是超过期间客户端就去master请求数据。通常而言,slave能够定时主动向master要求续租并更新数据,master在数据发生变化时也能够主动通知slave,不一样方式的选择也在于可用性与一致性之间进行权衡。
租约机制也能够解决主备之间网络不通致使的双主脑裂问题,亦即:主备之间原本心跳连线的,可是忽然之间网络不通或者暂停又恢复了或者太繁忙没法回复,这时备机开始接管服务,可是主机依然存活能对外服务,这是就发生争夺与分区,可是引入lease的话,老主机颁发给具体server的lease必然较旧,请求就失效了,老主机自动退出对外服务,备机彻底接管服务。
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
https://raft.github.io/
https://en.wikipedia.org/wiki...
https://lamport.azurewebsites...
http://www.infoq.com/cn/artic...
https://en.wikipedia.org/wiki...
从Paxos到ZooKeeper
分布式java应用
大数据日知录
http://m635674608.iteye.com/b...