点击上方“朱小厮的博客”,选择“设为星标”

后台回复"书",获取

后台回复“k8s”,可领取k8s资料

-     前言    -

分布式中一致性是非常重要的,分为弱一致性和强一致性。现在主流的一致性协议一般都选择的是弱一致性的特殊版本:最终一致性。下面就从分布式系统的基本原则讲起,再整理一些遵循这些原则的协议或者机制,争取通俗易懂。但是要真正实施起来把这些协议落地,可不是一篇文章能说清楚的,有太多的细节,要自己去看论文呐(顺着维基百科找就行了)。

-     基本原则与理论    -

CAP(Consistency一致性,Availability可用性,Partition tolerance分区容错性)理论是当前分布式系统公认的理论,亦即一个分布式系统不可能同时满足这三个特性,只能三求其二。对于分布式系统,P是基本要求,如果没有P就不是分布式系统了,所以一般都是在满足P的情况下,在C和A之间寻求平衡。

ACID(Atomicity原子性,Consistency一致性,Isolation隔离性,Durability持久性)是事务的特点,具有强一致性,一般用于单机事务,分布式事务若采用这个原则会丧失一定的可用性,属于CP系统。

BASE(Basically Availabe基本可用,Soft state软状态,Eventually consistency最终一致性)理论是对大规模的互联网分布式系统实践的总结,用弱一致性来换取可用性,不同于ACID,属于AP系统。

-     2PC    -

2 Phase Commit,两阶段提交,系统有两个角色协调者和参与者,事务提交过程分为两阶段:

  1. 提交事务请求(投票阶段)

  • 协调者向参与者发送事务内容,询问是否可以执行事务提交操作,等待响应

  • 参与者执行事务操作,并将undo和redo日志记录

  • 参与者回复协调者,执行成功则回Yes否则No

  • 执行事务提交(执行阶段)

    • 如果都是参与者都回复Yes,则协调者向参与者发送提交请求,否则发送回滚请求

    • 参与者根据协调者的请求执行事务提交或回滚,并向协调者发送Ack消息

    • 协调者收到所有的Ack消息过后判断事务的完成或者中断

    该协议可以视为强一致的算法,通常用来保证多份数据操作的原子性,也可以实现数据副本之间的一致性,实现简单,但是缺点也很多,比如单点故障(协调者挂了整个系统就没法对外服务,任一节点挂了事务就没法执行,没有容错机制)、阻塞(两个阶段都涉及同步等待阻塞,极大降低了吞吐量)、数据不一致(参与者回复Yes/No后如果因为网络原因没有收到提交/中断请求,此时它就不知道该如何操作了,导致集群数据不一致)……

    2PC有些优化手段:超时判断机制,比如协调者发出事务请求后等待所有参与者反馈,若超过时间没有搜集完毕所有回复则可以多播消息取消本次事务;互询机制,参与者P回复yes后,等待协调者发起最终的commitabort,如果没收到那么可以询问其他参与者Q来决定自身下一步操作,避免一直阻塞(如果其他参与者全都是等待状态,那么P也只能一直阻塞了)。所以2PC的阻塞问题是没办法彻底解决的。

    当然,如果网络环境较好,该协议一般还是能很好的工作的,2PC广泛应用于关系数据库的分布式事务处理,如mysql的内部与外部XA都是基于2PC的,一般想要把多个操作打包未原子操作也可以用2PC。

    -     3PC    -

    3 Phase Commit,三阶段提交,是二阶段提交的改进,系统也有两个角色协调者和参与者,事务提交过程分为三阶段:

    1. 事务询问(canCommit)

    • 协调者向参与者发送一个包含事务内容的询问请求,询问是否可以执行事务并等待

    • 参与者根据自己状态判断并回复yes、no

  • 执行事务预提交(preCommit)

    • 若协调者收到全是yes,就发送preCommit请求否则发布abort请求

    • 参与者若收到preCommit则执行事务操作并记录undo和redo然后发送Ack,若收到abort或者超时则中断事务

  • 执行事务提交(doCommit)

    • 协调者收到所有的Ack则发送doCommit请求,若收到了No或者超时则发送abort请求

    • 参与者收到doCommit就执行提交并发送ACk,否则执行回滚并发送Ack

    • 协调者收到Ack判断是完成事务还是中断事务

    三阶段相对于两阶段的改善就是把准备阶段一分为二,亦即多了一个canCommit阶段,按我理解这样就类似于TCP的三步握手,多了一次确认,增大了事务执行成功的概率。而且3PC的协调者即使出了故障,参与者也能继续执行事务所以解决了2PC的阻塞问题,但是也可能因此导致集群数据不一致。

    -     Paxos    -

    上面两个协议的协调者都需要人为设置而无法自动生成,是不完整的分布式协议,而Paxos 就是一个真正的完整的分布式算法。系统一共有几个角色:Proposer(提出提案)、Acceptor(参与决策)、Learner(不参与提案,只负责接收已确定的提案,一般用于提高集群对外提供读服务的能力),实践中一个节点可以同时充当多个角色。提案选定过程也大概分为2阶段:

    1. Prepare阶段

    • Proposer选择一个提案编号M,向Acceptor某个超过半数的子集成员发送该编号的Prepare请求

    • Acceptor收到M编号的请求时,若M大于该Acceptor已经响应的所有Prepare请求的编号中的最大编号N,那么他就将N反馈给Proposer,同时承诺不会再批准任何编号小于M的提案

  • Accept阶段

    • 如果Proposer收到超过半数的Acceptor对于M的prepare请求的响应,就发送一个针对[M,V]提案的Accept请求给Acceptor,其中V是收到的响应编号中编号的最大的提案值,如果响应中不包括任何提案值,那么他就是任意值

    • Acceptor收到这个针对[M,V]的Accept请求只要改Acceptor尚未对大于M编号的提案做出过响应,他就通过这个提案

  • Learn阶段(本阶段不属于选定提案的过程)

    • Proposer将通过的提案同步到所有的Learner

    Paxos协议的容错性很好,只要有超过半数的节点可用,整个集群就可以自己进行Leader选举,也可以对外服务,通常用来保证一份数据的多个副本之间的一致性,适用于构建一个分布式的一致性状态机。

    Google的分布式锁服务Chubby就是用了Paxos协议,而开源的ZooKeeper使用的是Paxos的变种ZAB协议。

    -     Raft    -

    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,然后给自己投票并向其它结点发投票请求。直到以下三种情况:

    • 它赢得选举;

    • 另一个节点成为Leader;

    • 一段时间没有节点成为Leader。

    在选举期间,Candidate可能收到来自其它自称为Leader的写请求,如果该Leader的term不小于Candidate的当前term,那么Candidate承认它是一个合法的Leader并回到Follower状态,否则拒绝请求。

    如果出现两个Candidate得票一样多,则它们都无法获取超过半数投票,这种情况会持续到超时,然后进行新一轮的选举,这时同时的概率就很低了,那么首先发出投票请求的的Candidate就会得到大多数同意,成为Leader。

    在Raft协议出来之前,Paxos是分布式领域的事实标准,但是Raft的出现打破了这一个现状(raft作者也是这么想的,请看论文),Raft协议把Leader选举、日志复制、安全性等功能分离并模块化,使其更易理解和工程实现,将来发展怎样我们拭目以待(挺看好)。

    Raft协议目前被用于 cockrouchDB,TiKV等项目中,据我听的一些报告来看,一些大厂自己造的分布式数据库也在使用Raft协议。

    -     Gossip    -

    Gossip协议与上述所有协议最大的区别就是它是去中心化的,上面所有的协议都有一个类似于Leader的角色来统筹安排事务的响应、提交与中断,但是Gossip协议中就没有Leader,每个节点都是平等的。

    每个节点存放了一个key,value,version构成的列表,每隔一定的时间,节点都会主动挑选一个在线节点进行上图的过程(不在线的也会挑一个尝试),两个节点各自修改自己较为落后的数据,最终数据达成一致并且都较新。节点加入或退出都很容易。

    去中心化的Gossip看起来很美好:没有单点故障,看似无上限的对外服务能力……本来随着Cassandra火了一把,但是现在Cassandra也被抛弃了,去中心化的架构貌似难以真正应用起来。归根到底我觉得还是因为去中心化本身管理太复杂,节点之间沟通成本高,最终一致等待时间较长……往更高处看,一个企业(甚至整个社会)不也是需要中心化的领导(或者制度)来管理吗,如果没有领导(或者制度)管理,大家就是一盘散沙,难成大事啊。

    事实上现代互联网架构只要把单点做得足够强大,再加上若干个强一致的热备,一般问题都不大。

    -     NWR 机制    -

    首先看看这三个字母在分布式系统中的含义:

    N:有多少份数据副本;
    W:一次成功的写操作至少有w份数据写入成功;
    R:一次成功的读操作至少有R份数据读取成功。

    NWR值的不同组合会产生不同的一致性效果,当W+R>N的时候,读取操作和写入操作成功的数据一定会有交集,这样就可以保证一定能够读取到最新版本的更新数据,数据的强一致性得到了保证,如果R+W<=N,则无法保证数据的强一致性,因为成功写和成功读集合可能不存在交集,这样读操作无法读取到最新的更新数值,也就无法保证数据的强一致性。

    版本的新旧需要版本控制算法来判别,比如向量时钟。

    当然R或者W不能太大,因为越大需要操作的副本越多,耗时越长。

    -     Quorum 机制    -

    Quorom机制,是一种分布式系统中常用的,用来保证数据冗余和最终一致性的投票算法,主要思想来源于鸽巢原理。在有冗余数据的分布式存储系统当中,冗余数据对象会在不同的机器之间存放多份拷贝。但是同一时刻一个数据对象的多份拷贝只能用于读或者用于写。

    分布式系统中的每一份数据拷贝对象都被赋予一票。每一个操作必须要获得最小的读票数(Vr)或者最小的写票数(Vw)才能读或者写。如果一个系统有V票(意味着一个数据对象有V份冗余拷贝),那么这最小读写票必须满足:

    • Vr + Vw > V

    • Vw > V/2

    第一条规则保证了一个数据不会被同时读写。当一个写操作请求过来的时候,它必须要获得Vw个冗余拷贝的许可。而剩下的数量是V-Vw 不够Vr,因此不能再有读请求过来了。同理,当读请求已经获得了Vr个冗余拷贝的许可时,写请求就无法获得许可了。

    第二条规则保证了数据的串行化修改。一份数据的冗余拷贝不可能同时被两个写请求修改。

    Quorum机制其实就是NWR机制。

    -     Lease 机制    -

    master给各个slave分配不同的数据,每个节点的数据都具有有效时间比如1小时,在lease时间内,客户端可以直接向slave请求数据,如果超过时间客户端就去master请求数据。一般而言,slave可以定时主动向master要求续租并更新数据,master在数据发生变化时也可以主动通知slave,不同方式的选择也在于可用性与一致性之间进行权衡。

    租约机制也可以解决主备之间网络不通导致的双主脑裂问题,亦即:主备之间本来心跳连线的,但是突然之间网络不通或者暂停又恢复了或者太繁忙无法回复,这时备机开始接管服务,但是主机依然存活能对外服务,这是就发生争夺与分区,但是引入lease的话,老主机颁发给具体server的lease必然较旧,请求就失效了,老主机自动退出对外服务,备机完全接管服务。

    参考:

    https://en.wikipedia.org/wiki/Two-phase_commit_protocol
    https://en.wikipedia.org/wiki/Three-phase_commit_protocol
    https://en.wikipedia.org/wiki/Paxos_(computer_science)
    https://raft.github.io/
    https://en.wikipedia.org/wiki/Raft_(computer_science)
    https://lamport.azurewebsites.net/pubs/paxos-simple.pdf
    http://www.infoq.com/cn/articles/raft-paper
    https://en.wikipedia.org/wiki/Gossip_protocol
    从Paxos到ZooKeeper
    分布式java应用
    大数据日知录
    http://m635674608.iteye.com/blog/2343038

    
    想知道更多?扫描下面的二维码关注我后台回复"技术",加入技术群后台回复“k8s”,可领取k8s资料【精彩推荐】
    
    • ClickHouse到底是什么?为什么如此牛逼!

    • 原来ElasticSearch还可以这么理解

    • 面试官:InnoDB中一棵B+树可以存放多少行数据?

    • 架构之道:分离业务逻辑和技术细节

    • 星巴克不使用两阶段提交

    • 面试官:Redis新版本开始引入多线程,谈谈你的看法?

    • 喜马拉雅自研网关架构演进过程

    • 收藏:存储知识全面总结

    • 微博千万级规模高性能高并发的网络架构设计

详解分布式一致性机制相关推荐

  1. base cap 分布式_高并发架构系列:详解分布式一致性ACID、CAP、BASE,以及区别

    在面试环节,经常会问CAP.BASE等相关的分布式理论,其实这些名词主要还是来自于分布式的一致性,今天主要介绍分布式一致性:强一致性.最终一致性.ACID.CAP等理论. 分布式一致性的背景 随着分布 ...

  2. 详解LibraBFT共识机制

    [Libra 技术解读]详解LibraBFT共识机制 ---------------- 版权声明:本文为CSDN博主「百度超级链xuper」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上 ...

  3. 【Libra 技术解读】详解LibraBFT共识机制

    Libra技术系列解读 往期回顾: move语言简介 move语法.解释器和验证器 本期详解"LibraBFT共识机制" Libra白皮书中关于共识机制的描述 Libra 区块链采 ...

  4. 详解JVM类加载机制

    详解JVM类加载机制 笔者的笔记都记录在有道云里面,因为公司原因办公电脑无法使用有道云,正好借此机会整理下以前的笔记顺便当做巩固复习了,也因为记笔记的时候不会记录这些知识来源何地,所以如果发现原创后可 ...

  5. c语言handler指针,详解C++ new-handler机制

    当 operator new 不能满足一个内存分配请求时,它抛出一个 exception(异常).很久以前,他返回一个 null pointer(空指针),而一些比较老的编译器还在这样做.你依然能达到 ...

  6. 详解自注意力机制及其在LSTM中的应用

    详解自注意力机制及其在LSTM中的应用 注意力机制(Attention Mechanism)最早出现在上世纪90年代,应用于计算机视觉领域.2014年,谷歌Mnih V等人[1] 在图像分类中将注意力 ...

  7. Linux系统调用详解(实现机制分析)

    为什么需要系统调用   linux内核中设置了一组用于实现系统功能的子程序,称为系统调用.系统调用和普通库函数调用非常相似,只是系统调用由操作系统核心提供,运行于内核态,而普通的函数调用由函数库或用户 ...

  8. TCP-IP详解:重传机制

    参考教材:TCP-IP Guide 超时重传是TCP保证数据传输可靠性的又一大措施,本文主要介绍重传TCP报文的两大举措:超时重传和快速重传 超时重传机制 超时重传指的是,发送数据包在一定的时间周期内 ...

  9. 详解分布式协调服务 ZooKeeper

    这篇文章主要会介绍 Zookeeper 的实现原理以及常见的应用 在 2006 年,Google 发表了一篇名为 The Chubby lock service for loosely-coupled ...

最新文章

  1. 聚类(Clustering)定义、聚类思想及形式、距离的度量
  2. ASP.NET MVC IOC 之AutoFac攻略
  3. VTK:图表之ConstructTree
  4. ftp如何预览图片 解决方案
  5. uboot启动第二阶段——start_armboot
  6. [Luogu 2090]数字对
  7. 设置TOMCAT SESSIONID 字符长度和生成算法
  8. Sql2Bean代码生成器
  9. 什么是数据库?以及主流的数据库有哪些
  10. matlab显示数据类型,MATLAB查看数据类型
  11. 帝国cms html5 编辑器,帝国cms后台编辑器自动排版插件
  12. 软件测试最容易陷入的28个误区
  13. RLC串联电路截止频率
  14. java下载basic_Java-basic(1)
  15. 94.(leaflet之家)leaflet态势标绘-进攻方向绘制(燕尾)
  16. IE 浏览器中不能使remove删除节点的解决方法
  17. chrome 多窗口 android,谷歌提前放出安卓7.0开发者预览版:多窗口+画中画
  18. husky配置 => git 日志提交规范限制, eslint检查
  19. Github pages个人域名添加SSL
  20. UML-在线声称uml序列图

热门文章

  1. 原型的指向是否可以改变 原型最终指向了哪里 原型指向改变如何添加方法和访问
  2. Nginx教程-location配置
  3. mkdir和mkdir-p的区别
  4. 210129阶段三调试、进程间通信-共享内存
  5. head first servlet jsp 学习笔记
  6. Python处理word文件
  7. Hackthissite realistic 6解密题后的记录
  8. Ixia张林辉:测试系统让SDN更“迷人”
  9. 汇编实现大写转小写函数(to_lower)
  10. 《NIOSII那些事儿》rev7.0 PDF版本发布