原文连接: blog.wangriyu.wang/2018/06-Dis…html
CAP 定理指出对于一个分布式系统来讲,不可能同时知足如下三点:mysql
一个分布式系统里面,节点组成的网络原本应该是连通的。然而可能由于一些故障或者延时,使得有些节点之间不连通了,整个网络就分红了几块区域。数据就散布在了这些不连通的区域中,这就叫分区。当你一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分就访问不到这个数据了。这时分区就是没法容忍的。提升分区容忍性的办法就是将一个数据项复制到多个节点上,那么出现分区以后,这一数据项就可能分布到各个区里,容忍性就提升了。然而,要把数据复制到多个节点,就会带来一致性的问题,就是多个节点上面的数据多是不一致的。要保证一致,每次写操做就都要等待所有节点写成功,而这等待又会带来可用性的问题。总的来讲就是,数据存在的节点越多,分区容忍性越高,但要复制更新的数据就越多,一致性就越难保证。为了保证一致性,更新全部节点数据所须要的时间就越长,可用性就会下降 -- 来自知乎邬江的回答算法
CAP 理论实际想表达的是任何分布式系统不能同时知足强一致性、高可用性和较好的分区容错性sql
RDBMS: Relational Database Management System,关系型数据库管理系统数据库
由 CAP 定理可知数据库的设计须要权衡取舍,因此能够把数据库大体分为三类:服务器
分布式和集群的区别:网络
分布式: 不一样的多台服务器上面部署不一样的服务模块,他们之间经过 Rpc/HTTP 等方式进行通讯和调用,对外提供服务和组内协做架构
集群: 不一样的多台服务器上面部署相同的服务模块,经过分布式调度软件进行统一的调度,对外提供服务和访问并发
ACID 指的是传统数据库中事务操做所具有的四个特性:异步
BASE 理论是对 CAP 理论的延伸,核心思想是虽然没法作到强一致性 (Strong Consistency),但能够采用适合的方式达到最终一致性 (Eventual Consitency)
BASE 包含三部分:
ACID 隶属于 CA,是传统数据库经常使用的设计理念,追求强一致性模型
BASE 隶属于 AP,支持的是大型分布式系统,提出经过牺牲强一致性得到高可用性
但在实际的分布式场景中,不一样业务单元和组件对数据一致性的要求是不一样的,所以在具体的分布式系统架构设计过程当中,ACID 特性与 BASE 理论每每会结合在一块儿使用。好比总体知足 BASE,局部知足 ACID。
上述最终一致性的不一样方式能够进行组合,例如单调读一致性和读己之所写一致性就能够组合实现。而且从实践的角度来看,这二者的组合,读取本身更新的数据,和一旦读取到最新的版本不会再读取旧版本,对于此架构上的程序开发来讲,会少不少额外的烦恼。
从服务端角度,如何尽快将更新后的数据分布到整个系统,下降达到最终一致性的时间窗口,是提升系统的可用度和用户体验很是重要的方面。
为了解决分布式的一致性问题,出现了不少一致性协议和算法,好比二阶段提交协议,三阶段提交协议和 Paxos 算法
在异步通讯场景,即便只有一个进程失败了,也没有任何算法能保证非失败进程可以达到一致性。
异步通讯与同步通讯的最大区别是没有时钟、不能时间同步、不能使用超时、不能探测失败、消息可任意延迟、消息可乱序
分布式事务用于在分布式系统中保证不一样节点之间的数据一致性,一般会涉及到多个数据库。分布式事务处理的关键是必须有一种方法能够知道事务在任何地方所作的全部动做,提交或回滚事务的决定必须产生统一的结果(所有提交或所有回滚)。
DRDA: Distributed Relational Database Architecture,分布式关系数据库架构
XA 规范是 X/Open 组织(即如今的 Open Group) 关于分布式事务处理 (DTP) 模型的处理规范。
DTP 模型包括应用程序 AP、事务管理器 TM、资源管理器 RM、通讯资源管理器 CRM 四部分。常见的事务管理器 TM 是交易中间件,常见的资源管理器 RM 是数据库,常见的通讯资源管理器 CRM 是消息中间件。交易中间件是必需的,由它通知和协调相关数据库的提交或回滚。
规范描述了全局的事务管理器与局部的资源管理器之间的接口。XA 规范的目的是容许的多个资源(如数据库,应用服务器,消息队列,等等)在同一事务中访问,这样可使 ACID 属性跨越应用程序而保持有效。
XA 使用两阶段提交或三阶段提交来保证全部资源同时提交或回滚任何特定的事务
当一个事务跨越多个节点时,为了保持事务的 ACID 特性,须要引入一个做为协调者的组件来统一掌控全部节点(称做参与者)的操做结果并最终指示这些节点是否要把操做结果进行真正的提交。因此两阶段提交 (Two-phase Commit) 的算法思路能够归纳为: 参与者将操做成败通知协调者,再由协调者根据全部参与者的反馈情报决定各参与者是否要提交操做仍是停止操做。
两阶段提交须要的条件:
两个阶段分别为:
第一阶段也被称做投票阶段,即各参与者投票是否要继续接下来的提交操做
无论最后结果如何,第二阶段都会结束当前事务
一、同步阻塞问题。执行过程当中,全部参与节点都是事务阻塞型的。当参与者占有公共资源时,其余第三方节点访问公共资源都将处于阻塞状态
二、单点故障。因为协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤为在第二阶段,协调者发生故障,那么全部的参与者还都处于锁定事务资源的状态中,而没法继续完成事务操做。(若是是协调者挂掉,能够从新选举一个协调者,可是没法解决由于协调者宕机致使的参与者处于阻塞状态的问题)
三、数据不一致。在第二阶段中,当协调者向参与者发送 commit 请求以后,发生了局部网络异常或者在发送 commit 请求过程当中协调者发生了故障,这会致使只有一部分参与者接受到了 commit 请求。而在这部分参与者接到 commit 请求以后就会执行 commit 操做。可是其余部分未接到 commit 请求的机器则没法执行事务提交,因而整个分布式系统便出现了数据不一致的现象
四、二阶段提交存在一个没法解决的问题:
对于现有模型,可能会出现的错误和相应的措施以下
关于第三个问题的详细描述以下:
协调者挂了,RM3 也挂了,此时分两种状况,RM3 是否执行了最后的事务操做:
最后这个问题就是 2PC 没法解决的问题,但 3PC 能够必定程度上解决
三阶段提交 (Three-phase Commit) 是针对两阶段缺点而设计的改进型,相比较两阶段提交,作出如下两点改动:
三个阶段分为:
此图中若是某条 PreCommit 消息未到达或者超时,RM 应该中断本身本地的事务,就跟下图中 Abort 超时同样
根据状况分为两种情形:
图中 RM3 在第二阶段未正常响应 ACK,可能有以下状况:
在第三阶段,若是参与者没法及时接收到来自协调者的 DoCommit 或者 Abort 请求时,会在等待超时以后,会继续进行事务的提交
这么作是有必定考究的,由于能进入第三阶段,说明协调者确定在第二阶段发起了 PreCommit 请求,而发起 PreCommit 请求的前提是第一阶段全部参与者都响应了 Yes,这代表全部参与者当时的状态都是乐观的,那么第三阶段参与者就算没有按时收到来自协调者的 DoCommit 请求,也继续完成本地事务的提交,这样完成全局事务的可能性仍是很大的,这一点是针对 2PC 数据不一致问题的
可是这一点也会形成 3PC 的一致性缺陷: 若是此时是协调者对某个 RM 发出的 Abort 请求超时,而那个 RM 继续完成本地事务的提交,这就会形成与其余进行回滚操做的节点数据不一致(这种状况几率较小)
对应 2PC 的缺陷,咱们能够看到 3PC 解决了很多问题,一方面默认的超时机制能够避免单点故障形成的资源长久阻塞的问题;另外一方面状态确认和默认超时提交也能够解决 2PC 的数据不一致问题(虽然这会形成 3PC 本身的不一致问题,可是由于 3PC 的机制,这种几率更小)
至于前面提到的 2PC 没法解决的问题,3PC 又是怎么解决的呢?
咱们能够回想 2PC 的问题,冲突的条件就是 RM3 第一阶段投了反对票,而这件事只有原协调者知道,挂掉的二者执行了回滚操做,而新协调者和正常节点会执行提交操做;可是 3PC 将准备阶段分为两步能够确保最终事务操做以前,你们都知道投票结果,描述以下:
其实只要没有执行事务最终的提交或者回滚都不影响最终结果,只要后面 RM3 恢复后查询协调者并执行相同的操做便可
这时候新协调者出现后,只要查看正常节点的状态就能够知道发送提交仍是回滚指令: 若是都是 Commited 或者 PreCommit 状态,说明第一轮投票结果都是 Yes,不然不可能进入 PreCommit 状态,因此新协调者发送提交指令便可;若是存在节点的状态是 Cancel,说明第一轮投票结果有反对票,那么新协调者发送回滚指令便可。可能这里会有个疑问,讲 DoCommit 的时候咱们说过第二阶段参与者的 ACK 可能没法正常响应协调者,若是是 RM3 第一轮投了支持票后面进入 PreCommit 状态时没有把 ACK 正常响应给协调者,所以协调者发送了 Abort 指令给 RM3 后挂了,RM3 收到指令后也挂了,此时仍是会形成 RM3 回滚,而新协调者和正常节点执行提交的情况,这里其实 3PC 好像也无法解决,可是这种状况的几率你能够估算一下,原本协调者发送指令挂了而后某些参与者执行后也挂了的几率自己就低了,还要知足挂的协调者在投完支持票后响应超时引发协调者发送 Abort 指令的几率,那就更小了
咱们用一个实际生活的例子来讲明并理解这个过程:
假设协调者是牧师,而参与者是一男一女,他们来到教堂单独跟牧师见面并传达是否想跟另外一方创建更深的关系的信息
第一步男女双方给牧师递了小纸条,上面写着是否想跟另外一方创建更深的关系,而且各自准备好了信物 (Undo&Redo)
第二步牧师看过以后,若是双方都写“是”,那么告知双方交换信物表示能够继续深交;若是有一方写“否”,那么告知双方分手吧,信物也撤了吧
可是这里 2PC 没法解决一个问题: 假如男方写的纸条信息是“否”,而牧师看过以后先告诉男方你把信物撤了吧,大家不合适,可是牧师紧接着心脏病犯了住院了,而男方收到消息后也撤了信物准备分手,但是男方忽然被人打了住院昏迷;新牧师出现,继续询问女方的意见,由于不知道男方的意见,他们可能会促成一桩不美满的关系
第一步男女双方仍是递了小纸条,表示本身的意愿
第二步牧师看过以后,若是双方都写“是”,那么先告知双方准备信物;若是有一方写“否”,那么告知双方不用准备信物了;双方收到消息后再回应说本身知道了
第三步牧师确认双方的回应后,告知双方最后是否在一块儿,是否交换信物
在这里假如第三步牧师也是先告知男方后突发心脏病住院,而男方也是收到消息后被打昏迷,此时新牧师出现后能够查看女方是否准备了信物而完成最后的决定,由于假如男方本来是不一样意,那么第二步双方确定是没有准备信物的,而假如男方是赞成的,那么双方确定是准备了信物的,那么新牧师能够放心宣布双方能够在一块儿
3PC 还对双方都引入了超时,2PC 中只有牧师没收到消息时会取消事务,而 3PC 中若是男女双方长时间没有收到牧师消息后也会执行本身的决定,避免了 2PC 中一样情形时男女双方在这里一直耗着(阻塞)而错过了下一任。只不过咱们提到了若是第三步牧师是由于长时间没有收到男方的消息时也取消了事务,虽然这时候男女双方都是赞成的,可是仍是会被取消事务,这也可能形成新的不一致问题,可是相对来讲几率就小得多了
经过上述过程可知最后不管是二阶段提交仍是三阶段提交都没法完全解决分布式的一致性问题,若是系统正常运行都能知足强一致性,可是若是出现意外仍是会致使不一致,不过能够经过其余手段达到一致性,好比分区数据恢复或者事务补偿机制或者采用其余一致性算法
复杂的数据恢复能够参见 SVN 的版本控制,可能能够自动合并,也可能会发生冲忽然后须要人工干预
简单的数据恢复能够参见 Mysql 的主从同步,数据能够自动从主库导到从库
合并分区数据达成一致并非最困难的,更困难的是处理分区过程当中产生的错误。当分区操做引发错误,能够经过事务补偿补救错误,这多是人工的也多是自动的
好比 MQ 消息事务和 TCC 事务协议就是一种补偿机制: