CAP
在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
一致性(Consistency)(等同于所有节点访问同一份最新的数据副本)可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据)分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。)
根据定理,分布式系统只能满足三项中的两项而不可能满足全部三项。
理解CAP理论的最简单方式是想象两个节点分处分区两侧。
-
AP:允许至少一个节点更新状态会导致数据不一致,即丧失了C性质。会导致全局的数据不一致。
-
CP:为了保证数据一致性,将分区一侧的节点设置为不可用,那么又丧失了A性质。分区同步会导致同步时间无限延长(也就是等数据同步完成之后才能正常访问)
-
CA:两个节点可以互相通信,才能既保证C又保证A,这又会导致丧失P性质。这样的话就分布式节点受阻,无法部署子节点,放弃了分布式系统的可扩展性。因为分布式系统与单机系统不同,它涉及到多节点间的通讯和交互,节点间的分区故障是必然发生的,所以在分布式系统中分区容错性是必须要考虑的。

分布式一致性协议
为了解决分布式系统的一致性问题,在长期的探索研究过程中,涌现出了一大批经典的一致性协议和算法,其中最著名的就是二阶段提交协议、三阶段提交协议和Paxos算法。
两段式提交协议(two-phase commit)
分布式事务指设计操作多个数据库的事务,在分布式系统当中,各个节点之间存在物理上的独立,通过网络进行协调。
两段式提交协议(two-phase commit)指在计算机网络及数据库领域内,为了是分布式的每个节点在进行事务提交的时候都保持一致性的算法。在分布式系统当中虽然都可以知道自己的操作是否成功,但是却无法直接知道其他节点的操作是否成功
在一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个座位协调者的组件来控制所有的节点(称做参与者)的操作结果,并最终指示这些节点是否真正提交结果。
因此,二段式提交算法的思路可以概括为:参与者将操作成功失败的结果通知协调者,再由协调者根据所有参与者的反馈决定各参与者是提交操作还是终止操作。
1.Prepare(准备阶段)
事务协调者(事务管理器)给每个参与者(源管理器)都发送Prepare消息,每个参与者要么直接返回失败(如权限验证失败),要么本地执行事务,写入本地的redo log和undo log但是不进行提交,这就是“一种万事俱备,只欠东风”的状态。
2.Commit(提交阶段)
如果协调者接受到了参与者的失败消息,则给每一个参与者都发送回滚消息,否则发送提交消息,参与者根据协调者的指令执行提交或者回滚操作,释放在所有事物处理过程中使用的锁资源。
图示

两段式提交的缺点
- 同步阻塞问题:
在执行过工程中,所有的参与者的任务都是阻塞执行的。
- 单点故障:
所有的请求都需要经过协调者,当协调者发生故障时,所有的参与者都会被阻塞。
- 数据不一致:
在二节点提交的第2节点,在协调者向参与者发送Commit(提交)请求后发生了局部网络异常,或者在发送Commit请求过程中协调者发生了故障,导致只有一部分参与组合收到了Commit请求,于是整个分布式系统出现了数据不一致的现象,这一现象,也被称为脑裂。
- 协调者宕机后事务状态丢失:
协调者在 发出Commit消息之后宕机,唯一接收到这条消息的参与者也宕机,及时通过协调者通过选举协议产生了新的协调者,这条事务的状态也是 不确定的。
三段式提交协议(Three-Phase Commit)
二段式提交的改进版本,具体的改进如下:
- 引入超时机制:在协调者和参与者中引入超时机制,如果协调者长时间接收不到参与者的反馈,则认为参与者执行失败。
- 在第一阶段和第二阶段都加入一个预准备阶段,以保证在最后的任务提交之前参与的节点的状态是一致的。也就是说,除了引入超时机制,三段式提交协议(3PC)把二段式提交协议(2PC)再次一分为二,这样3PC就有
CanCommit、PreCommit、DoCommit三个阶段。
1.CanCommit阶段
协调者向参与者者发送Commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
2.PreCommit阶段
协调者根据参与者的反应来决定是否继续进行,有一些的两种可能。
- 假如协调者从所有参与者那里获得的反馈都是Yes响应,就预执行事务。
- 假如有任意参与者向协调者发送了No响应,或者在等待超时之后协调者都没有收到参与者的Yes响应,则执行事务中断。这个阶段相当于二阶端提交协议第一阶段
3.DoCommit阶段
该阶段执行真正的事务提交,主要包括:
- 向协调者发送提交请求
- 参与者提交事务
- 参与者响应反馈(在事务完成之后向协调者发送Ack响应)
- 协调者确认完成事务

3PC存在的问题
3PC并数据不一致的问题,也就是在PreCommit阶段如果参与者接收到了预备提交的消息,当参与者完成事务的准备的时候(doCommit阶段的结果是abort),调用者出现了故障,部分参与者回滚了事务(部分未回滚),新上线的协调者无法知道调用的状态,而让处于PreCommit阶段的节点执行了事务,这时就造成了数据的不一致。
一般都采用两段式提交协议的改进版本,因为段数越多需要的通信次数就越多,对于网络的要求也就越高。
ACID理论和BASE理论
ACID 理论是对事务特性的抽象和总结,方便我们实现事务。你可以理解成:如果实现了操作的 ACID 特性,那么就实现了事务。而大多数人觉得比较难,是因为分布式 系统涉及多个节点间的操作。加锁、时间序列等机制,只能保证单个节点上操作的 ACID 特性,无法保证节点间操作的 ACID 特性。
至于Base理论,追求可用性,相对于ACID理论追求的一致性不同 CAP理论而言,保证一致性的条件的话一定会牺牲可用性。
集群的可用性是每个节点可用性的乘积,比如,假设 3 个节点的集群,每个节点的 可用性为 99.9%,那么整个集群的可用性为 99.7%,也就是说,每个月约宕机 129.6 分 钟,这是非常严重的问题。 而解决可用性低的关键在于,根据实际场景,尽量采用可用性 优先的 AP 模型。
**BASE 理论是 CAP 理论中的 AP 的延伸,是对互联网大规模分布式系统的实践 总结,强调可用性。**几乎所有的互联网后台分布式系统都有 BASE 的支持,这个理论很重 要,地位也很高。
Base理论的核心就是基本可用(Basically Available)和终一致性(Eventually consistent)。也有人会提到软状态(Soft state),在我看来,软状态描述的是实现服务可用性的时候系统数据的一种过渡状态,也就是说不同节点间,数据副本存在短暂的不一致。
基本可用的四板斧
以订票系统为例
流量削峰
咱们可以在不同的时间,出售不同区域的票,将访问请求错开,削弱请求峰值。比如,在春 运期间,深圳出发的火车票在 8 点开售,北京出发的火车票在 9 点开售
延迟响应
在春运期间,自己提交的购票请求,往往会在队列中排队等待处 理,可能几分钟或十几分钟后,系统才开始处理,然后响应处理结果
体验降级
比如用小图片来替代原始图片,通过降低图片的清晰度和 大小,提升系统的处理能力。
过载保护
比如把接收到的请求放在指定的队列中排队处理,如果请求等 待时间超时了(假设是 100ms),这个时候直接拒绝超时请求;再比如队列满了之后,就 清除队列中一定数量的排队请求,保护系统不过载,实现系统的基本可用。
最终一致性
最终一致性是指系统中所有的副本经过一段时间的异步同步之后,最终能够达到一个一致性的状态,也就是说在数据的一致性上存在一个短暂的延迟。
几乎所有的互联网系统采用的都是终一致性,只有在实在无法使用终一致性,才使用强 一致性或事务,比如,对于决定系统运行的敏感元数据,需要考虑采用强一致性,对于与钱 有关的支付系统或金融系统的数据,需要考虑采用事务。
也就是说能够使用最终一致性的业务就尽量使用最终一致性,因为强一致性会降低系统的可用性。