数据一致性
本地事务与分布式事务
本地事务
传统单机应用一般都会使用一个关系型数据库,好处是可以使用ACID事务特性。为保证数据一致性我们只需要开启一个事务,执行数据更新操作,然后提交事务或回滚事务。
分布式事务
一个应用需要同时访问两个或两个以上的数据库的的场景并不能依靠本地事务得以解决。这时候可以借助于分布式事务来保证一致性,也就是通常所说的两阶段提交协议(Two Phase Commit,2PC)和三阶段提交协议(Three Phase Commit,3PC)。
两阶段提交协议
两阶段提交,顾名思义分成两个阶段,先由一方提议并收集其他节点的反馈(准备阶段),再根据反馈决定提交或中止事务(执行阶段)。一般将提议的节点称为协调者(Coordinator),其他参与决议的节点称为参与者(Participants)。图5-9展示了协调者发起一个提议分别询问各参与者是否接受的场景,然后协调者根据参与者的反馈,提交或中止事务。如果参与者全部同意则提交,只要有一个参与者不同意就中止。
二阶段提交看起来确实能够提供原子性的操作,但不幸的是,二阶段提交存在一些明显的缺点。
同步阻塞问题
执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
单点故障
由于协调者的重要性,一旦协调者发生故障,参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。
数据不一致
在二阶段提交中,当协调者向参与者发送提交请求之后发生了局部网络异常,或者在发送提交请求过程中协调者发生了故障,就会导致只有一部分参与者接收到了提交请求。而这部分参与者接到提交请求之后就会执行提交操作,但是其他未接到提交请求的机器则无法执行事务提交。于是,整个分布式系统便出现了数据不一致性的现象。 由于二阶段提交存在以上缺陷,业界在二阶段提交的基础上做了改进,提出了三阶段提交。
三阶段提交协议
三阶段提交协议是二阶段提交协议的改进版,与两阶段提交相比,三阶段提交有两个改动点。其一是同时在协调者和参与者中都引入超时机制,其二则是把二阶段提交中的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。
相对于2PC,3PC主要解决的是单点故障问题,并减少阻塞。因为一旦参与者无法及时收到来自协调者的信息就会默认执行提交,而不会一直持有事务资源并处于阻塞状态。
传统分布式事务的问题
分布式事务能解决一部分数据一致性的问题,但在微服务架构中,传统分布式事务并不是实现数据一致性的最佳选择。
- 对于微服务架构来说,数据访问变得更加复杂.
- 不同的微服务经常使用不同的数据库。序列化以及锁的使用,都是当且仅当多个服务使用相同数据库的前提下才能正常工作。
- 服务在使用锁的过程中,持有锁的时间都是非常短的。但当数据被拆分了或者在不同的数据库存在重复数据的时候,锁定资源和序列化数据来保证一致性就会变成一个非常昂贵的操作,会给系统的吞吐量以及扩展性带来巨大的负担。
当下主流的分布式应用大都不会锁定被修改的数据,而是采用一种更为松散的方式来维护一致性,也就是所谓的最终一致性(Eventual Consistency)。
CAP理论
CAP理论指的是在一个分布式系统中,无法同时实现一致性(Consistency,C)、可用性(Availability,A)和分区容错性(Partition Tolerance,P)。
一致性意味着所有客户端同时看到相同的数据,无论它们连接到哪个节点。为此,无论何时将数据写入一个节点,都必须立即将数据转发或复制到系统中的所有其他节点,然后才能认为写入“成功”。
可用性意味着任何发出数据请求的客户端都会得到响应,即使一个或多个节点已关闭。另一种表述方式——分布式系统中的所有工作节点都能为任何一个请求返回有效响应。
分区是分布式系统中的通信中断——两个节点之间出现连接丢失或暂时的连接延迟。分区容错意味着集群必须继续工作,即使系统中的节点之间存在通信故障。
由于当前的网络硬件肯定会出现延迟丢包等通信异常问题,所以一般认为分区容错性必须实现。
BASE思想
BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性,应用可以采用适合的方式达到最终一致性。BASE是指基本可用(Basically Available)、软状态(Soft State)和最终一致性(Eventual Consistency)。
基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。
软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据都会有若干个副本,允许不同节点间副本同步的延时就是软状态的体现。
最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。CAP的一致性就是强一致性,这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响较大。弱一致性和强一致性相反,弱一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不会承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。BASE中的最终一致性可以看作是弱一致性的一种特殊情况。
即使无法做到强一致性,我们也可以采用合适的方式达到最终一致性,这点在微服务架构中表现得尤为明显。