专栏首页琦小虾的Binary分布式事务的实现思想

分布式事务的实现思想

分布式事务的实现思想

参考地址:《从银行转账失败到分布式事务:总结与思考》

分布式事务的基本概念与本地事务类似,都保证了 ACID 特性(见[本篇第二章](# 二. 事务的特性))。随着数据的规模越来越大,就出现了对业务的解构,包括数据层面的关系型数据库的垂直、水平分表,以及服务层面的拆分,将一个大服务拆分为后单独部署,甚至同时也将数据库独立出来。这时候本地数据库事务就不能满足多个数据库、异构系统的原子性、持久性了,需要使用分布式事务的方法。通常,分布式事务只需要保证原子性,通过保证原子性来保证应用层面的一致性,由本地事务保证隔离性和持久性。 从 CAP 特性上考虑,由于分布式事务存在网络分割的情况,所以一定需要满足分区容忍性,剩下的需要在一致性 (Consistency)可用性 (Available) 之间做权衡。下面提到各种分布式事务的实现方法与协议,都是需要在一致性与可用性之间权衡的。

1. 二阶段提交协议 (2PC)

二阶段提交 (Two-phase Commit Protocol) 是非常经典的强一致性、中心化的原子提交协议,协议中有两类节点:一个中心化协调者 (Coordinator) 节点N 个参与者 (Cohort) 节点。 2PC 每一次事务提交都分为两个阶段:

  1. 协调者询问所有的参与者是否可以提交事务,所有参与者向协调者投票;
  2. 协调者根据参与者的投票结果,做出是否事务可以全局提交的决定,并通知所有参与者执行该决定。

2PC 提交流程中,参与者不能改变自己的投票结果。此外,2PC 可以全局提交的前提,是所有参与者都同意提交事务。只要有一个参与者投票,选择放弃事务,则全局事务必须被放弃。

2PC 的优缺点:

  • 优点:
    • 强一致性。只要节点或者网络最终恢复正常,协议就能保证顺利结束;
    • 部分关系型数据库(如 Oracle)、框架直接支持;
  • 缺点:
    • 容错能力较差:比如节点宕机、超时的情况下,无法确定流程的状态,只能不断重试;
    • 性能较差,交互消息多,受最慢节点影响。
    • 访问共享资源你的时候,发生冲突和死锁的概率增高。随着数据库节点增多,这种趋势越来越严重。

2. 三阶段提交协议 (3PC)

相较于两阶段提交协议,三阶段提交协议 (3PC) 解决了阻塞问题,将两个阶段扩展为三个阶段,增加了超时机制。虽然解决了 2PC 情况下的阻塞问题,但一次提交要传递六次消息,延时很大。

3. TCC

TCC 是 Try, Commit, Cancel 的缩写,保证强一致性的同时,最大限度提高系统的可伸缩性与可用性。 假设一个完整的业务包含一组子业务:

  • Try:完成所有子业务检查,预留必要的业务资源,实现与其他事务的隔离;
  • Confirm:使用 Try 阶段预留的业务资源,真正执行业务;同时满足幂等性,支持重试;
  • Cancel:释放 Try 资源预留的业务资源,同样满足幂等性。

一次完整的交易,由一系列微交易的 Try 操作组成,如果所有 Try 操作都成功,最后由微交易框架统一 Confirm,否则统一 Cancel,这样实现了类似 2PC 的强一致性。TCC 的特点有:

  • Try 操作兼具资源操作与准备能力,没有单独的准备阶段 (Prepare),这样降低了提交协议的成本;
  • Try 操作由业务层保证原子性,这样也可以灵活选择业务资源的锁定粒度,而不是锁住整个资源,提高了整体的并发度;
  • TCC 的所有子业务都要事先自己的 Confirm, Cancel 操作,实现相应的补偿逻辑,所以需要较高的开发成本。

4. 基于消息的分布式事务

基于异步消息的事务机制,可以分为主事务从事务两部分。主事务本地先行提交,然后通过消息通知各个从事务,从事务收到主事务发来的消息后,各自进行本地提交。 由上面可以得知,这是一种异步事务机制,虽然只保证最终一致性,但可用性非常高,不会因为故障发生阻塞。 实现异步消息的事务机制有本地消息表事务消息两种方式,两种方式都可以保证主事务的提交与消息发送两者之间的原子性。下面以转账操作为例,转账操作分为四步:用户 A 扣钱,发送消息,用户 B 接受消息,用户 B 扣钱。其中前两步肯定是原子性的,本地消息表和事务消息的解决方案分别如下:

4.1 本地消息表

本地消息表的含义如字面意思,将消息存到本地数据库中,通过本地事务保证消息的存入。依旧是上面的转账例子,伪代码如下:

begin transaction:
	update user set account = account - 100 where userId = '00000000';
	insert into message(userId, amount, status) values ('00000000', 100, 1);
commit transaction

主事务通过这种本地数据库事务的方式,保证数据库中扣除 A 的操作,和向数据库中存入消息(类似于消费流水信息)的操作是原子性的。然后从事务定时的从数据库中拉取消息,然后执行。

4.2 事务消息

事务消息的部分见《Kafka 篇》第二章事务部分

将事务消息与本地消息表对比,事务消息不依赖于本地数据库存储消息,而是通过消息中间件保证本地事务与消息的原子性。但是实现了事务的消息队列比较少,不能通用化使用。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring技术知识点总结之六——Spring 事务传播等级

    Spring 事务传播有七个等级,假设有 methodA 调用 methodB,根据事务传播等级的设置,methodA 与 methodB 有如下效果:

    剑影啸清寒
  • 数据库技术知识点总结之一——事务

    标准的隔离级别中,Oracle 只有 Read committed, Serializable 两种,此外还有 ReadOnly, WriteOnly 两种级别...

    剑影啸清寒
  • Kafka技术知识总结之二——Kafka事务

    Kafka 事务与数据库的事务定义基本类似,主要是一个原子性:多个操作要么全部成功,要么全部失败。Kafka 中的事务可以使应用程序将消费消息、生产消息、提交消...

    剑影啸清寒
  • 记录分布式一致性中的几个概念

    事务是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元,狭义上的事务特指数据库事务。事务具有ACID属性。

    眯眯眼的猫头鹰
  • 快速学习-声明式事务管理

    大多数情况下声明式事务比编程式事务管理更好:它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。 事务管理代码的固定模式作为一种横切关注点,可以...

    cwl_java
  • 从银行转账失败到分布式事务:总结与思考

      思考这个问题的初衷,是有一次给朋友转账,结果我的钱被扣了,朋友没收到钱。而我之前一直认为银行转账一定是由事务保证强一致性的,于是学习、总结了一下分布式事务的...

    乱敲代码
  • 从银行转账失败到分布式事务的思考

      思考这个问题的初衷,是有一次给朋友转账,结果我的钱被扣了,朋友没收到钱。而我之前一直认为银行转账一定是由事务保证强一致性的,于是学习、总结了一下分布式事务的...

    JAVA葵花宝典
  • MySQL innoDB的事务隔离

    疑问: 那读提交和可重复读有什么区别吗? 是的,我也有这个疑问,读提交和可重复读不都是在提交后对其他事务可见。确实是这样 但是读提交在另一个事务提交后再去读取...

    居士
  • 3-1 SQL Server 2005的

    所谓事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。SQL Server 2005 提供了几种自动的可以通过编程来完成...

    py3study
  • spring事务传播特性

    通过上面对事物的说明,有编程经验的人应该都很清楚为什么需要失误了吧?那就是为了防止出现业务逻辑上的出错,如算错账转错钱等。

    居士

扫码关注云+社区

领取腾讯云代金券