分布式事务
基础概念
事务
事务(一般特指数据库事务)是由一组SQL语句组成的逻辑处理单元,具有ACID属性。
A(Atomic):原子性,事务作为一个整体被执行,要么全部执行,要么都不执行。
C(Consistency):一致性,事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态是指数据库中的数据应满足完整性约束。
I(Isolation):隔离性,多个事务并发执行时,一个事务的执行不应影响其它事务的执行。
D(Durability):持久性,事务一旦提交,其所作的修改就会永久保留到数据库中。
数据库事务是靠数据库本身来实现的。
分布式事务
随着微服务架构的普及,一个大型业务系统往往由多个子系统构成,这些子系统拥有各自独立的数据库。一个业务流程有时候需要多个子系统在一个事务中共同完成,即实现跨数据库的事务支持,这就是分布式事务。
分布式事务用于在分布式系统中保证不同节点之间的数据一致性,通常会涉及到多个数据库。
分布式事务理论基础
CAP理论
CAP理论指出对一个分布式系统来说,不可能同时满足以下三点:
- 一致性:同一个数据的多个副本,在同一时刻值是否相同。
- 可用性:服务一直可用,而且是正常响应时间。
- 分区容错性:允许发生网络分区。如果分区容错性不能满足,那使用分布式系统将失去意义。
分布式系统通常是CP型或AP型。CP型放弃可用性,追求强一致性,例如Zookeeper;AP型放弃强一致性,追求可用性。后面的BASE理论也是根据AP来扩展。
BASE理论
BASE理论是对CAP理论的延申,核心思想是虽然无法做到强一致性,但是可以采用合适的方案达到最终一致性。
基本可用(Basically Available):指分布式系统在出现故障的时候,允许损失部分可用性,保证核心可用性。
软状态(Soft State):指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。
最终一致性(Eventually Consistent):指系统中的所有数据副本经过一定时间后,最终能达到一致的状态。
常见分布式事务方案
在真实的业务场景中,如果能用单机数据库的事务来代替分布式事务,那就首选单机数据库事务。如果业务允许放弃强一致性,那就采用最终一致性原则来保证一致性(柔性事务),而最终一致性原则最常用的解决方案是利用可靠的MQ消息。
基于XA协议的2PC
两阶段提交,通过引入协调者来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。
两个阶段分别为:
- 准备阶段(投票阶段)
- 提交阶段(执行阶段)
准备阶段
- 事务协调者(事务管理器)给每个参与者(资源管理器)发送prepare消息,询问是否可以执行提交操作,并开始等待各参与者节点的响应。
- 参与者执行事务操作,并将Undo信息和Redo信息写入日志。
- 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个同意消息;如果参与者各节点的事务执行操作实际执行失败,则它返回一个中止的消息。
提交阶段
当协调者节点从所有参与者节点获得的响应消息都为同意时
- 协调者节点向所有参与者节点发出“正式提交”的请求
- 参与者节点正式完成操作,并释放整个事务期间内占用的资源
- 参与者节点向协调节点发送“完成”消息
- 协调者节点收到所有参与者节点反馈的“完成”消息后,完成事务
如果任一参与者在第一阶段返回的响应消息为中止,或者协调者节点在第一阶段的询问超市前无法获取所有参与者节点的响应消息时
- 协调者节点向所有参与者发出“回滚操作”的请求
- 参与者节点利用之前写入的undo消息执行回滚,并释放在整个事务期间内占用的资源
- 参与者节点向协调者节点发送“回滚完成”的消息
- 协调者节点收到所有参与者节点反馈的“回滚完成”消息后,取消事务
2PC方案实现起来简单,实际使用较少,主要因为以下问题:
- 性能问题。所有参与者在十五提交阶段处于同步阻塞状态。
- 可靠性问题。协调者存在单点故障。
- 数据一致性问题。阶段二中,如果发生局部网络问题,可能导致节点间数据不一致。
TCC事务
TCC属于补偿型分布式事务。TCC提供了一个编程模型,将实现分布式事务分为三个方法:Try、Confirm和Cancel,三个方法都需要业务编码实现。
Try:尝试待执行的业务。负责业务检查和资源的预留。
Confirm:执行业务。真正开始执行业务。
Cancel:取消执行的业务。释放占用的资源,并回滚。
Confirm/Cancel操作满足幂等性,如果Confirm或Cancel操作失败,将会不断重试直到执行完成。
TCC事务缺点是业务耦合性和开发成本较高。
TCC框架有ByteTCC。
本地消息表
本地消息表由ebay提出,核心思路是将分布式事务拆分成本地事务进行处理。
事务主动发起方建立事务消息表,事务发起方处理业务和记录事务消息在本地事务中完成,轮询事务消息表的数发送事务消息;事务被动方基于消息中间件消费事务消息表中的事务,成功时通过RPC接口修改消息状态,失败时不做处理等待重试。
事务主动方和事务被动方相关业务处理需要支持幂等。
MQ消息事务(可靠消息最终一致性)
消息事务的原理是将两个事务通过消息中间件进行异步解耦。
消息事务一定要保证业务操作与消息发送的一致性,如果业务操作成功,这条消息也一定投递成功。
消息事务依赖消息中间件的事务消息,基于消息中间件的二阶段提交实现,RocketMQ就支持事务消息。
执行流程:
- 发送prepare消息到消息中间件;
- 发送成功后,执行本地事务;
- 如果执行成功,则commit,消息中间件将消息下发至消费端;
- 如果执行失败,则rollback,消息中间件将这条prepare消息删除;
- 消费端接收到消息进行消费,如果消费失败,则不断重试。
最大努力通知
最大努力通知相比前两种方案实现简单,适用于一些最终一致性要求较底的业务,比如支付通知,短信通知。
以支付通知为例,支付之后支付系统会尽量去通知业务系统支付操作是否成功,但是会有一个最大通知次数,如果超过这个次数后还是通知失败,就不再通知。
分布式一致性算法
分布式存储系统通常采用维护多个副本来进行容错,提高系统可用性。要实现此目标,就必须解决分布式存储系统最核心的问题:维护多个副本数据的一致性。
Paxos
Raft
Raft协议相对Paxos的优点是容易理解、容易实现。
Raft使用leader和follower模型,并且假设集群只有一个leader。
Zab
(待续。。)