分布式事务概述

本文目的在于总结一下tcc学习过程中,对分布式事务和TCC的理解。主要讲述如下三个部分

  1. 分布式事务概念及常见方案
  2. 两阶段与三阶段提交的区别
  3. TCC框架
    1. 基本介绍
    2. 场景实现
    3. 主要原理
    4. 源码分析
    5. 其他tcc框架对比

0x1分布式事务概念及常见方案

分布式事务

普通数据库事务,都在一个实例上,不涉及远程IP通信,只在一个进程里就可以完成,而分布式事务通常是指跨进程跨ip的事务,举个例子,电商一个下单购买行为,有3个操作:下单、扣钱、扣减红包(或者加积分等),如果在一台机器上整个操作在一个事务里就可以完成,如果失败了也可以回滚。

但分布式事务则涉及多台机器,而且现在很多公司架构都是服务化,一个下单操作,账户服务和红包服务可能都在不同的机器上多实例部署。因此,如果此时下单异常,需要回滚就需要多个服务协调,这就是一个分布式事务。相比单机事务,难点在于事务被拆分到多个机器,commit和rollback都需要请求远程资源,系统可控性下降,系统状态变多,由此带来的一致性问题,性能问题都是难点。

ACID与CAP、BASE
传统关系型数据库强一致性遵循ACID。但是在分布式环境下,网络因素极为不可靠,ACID无法满足。分布式系统,CAP理论和BASE理论是系统设计的基础。

CAP
1. C一致性:数据的一致性,多节点数据是否一致。
2. A可用性:节点在合理的时间内返回合理的结果。(2个要求)
3. P分区容错性:无单点问题,多个节点且一个节点故障不影响整个集群。
一个分布式系统中,这三者只能同时满足两个。比如

  • 满足CP,降低可用性。一个节点A更新了数据,如果用户访问另一个节点B,如果要获取准确的数据,则必须等待B节点更新了数据,如果此时网络出现问题,用户必须等待网络修复,而假如时间较长,超出用户忍受范围,则可用性就很差。可见CA基本是冲突的。
    • 优先强一致性,适度牺牲A和P,如zookeeper。
      • 强一致性,zk尽量保证节点数据一致性,且保证最终一致性。zk的选举机制,导致zk需要有2N+1个节点,在数据同步方面,当数据需要同步时,只有系统N+1个节点都完成了数据同步后,zk才接受client连接。
      • 可用性:部分牺牲可用性——zk总是保证节点是可用的,保证大部分节点的数据是最新的,如果要保证数据一定是最新的,需要手动调用Sync()
      • 分区容错性:
        • 节点太多,会导致数据同步时间太长
        • 节点多了,选举leader时间会很耗时,需要引入observer
  • 满足AP,如果要达到较快的可用性,那么势必一致性就无法满足。但一般系统,一致性是可容忍的,即弱一致性,什么叫弱?就是说允许数据存在暂时的不一致性,一段时间内的不一致,允许数据存在中间状态:处理中。只要最终能达到一致性就可以。
    • 弱一致性,最终一致性。优先AP
      • HDFS——数据写入后不需要所有节点都保存完毕,只是保证最终都写入。
      • DNS——允许dns变更存在延迟

BASE

  1. basic available,基本可用
  2. soft transaction,柔性事务,允许事务存在中间状态,而不是原子,只能成功或失败,如处理中
  3. 最终一致性

角色及概念
一个分布式事务通常有两种角色:

  1. 协调者——事务源头,发起方,即根事务
  2. 参与者——事务参与方,也是子事务

这两个角色是一定要搞清楚的,举个例子。下单系统order发起分布式事务,下单后需要调用账户service和红包service,因此,order就是协调者,又是根事务,账户service和红包service就是两个参与者,又是2个子事务。

常见方案

  • 两阶段提交(2PC)atomikos框架
  • 三阶段提交(3PC)
    • TCC
      • ByteTCC
      • TCC-Transaction
      • Hymly
      • 自己实现,如《高性能系统服务构建》thrift hystrix方案
  • 其他方案(通常需要借助MQ)
    • EventSource事件溯源,黄勇《微服务下册》
    • 《人人都是架构师》里订单表和订单冗余表的一致性
      • 通过MQ对比数据
      • 通过日志增量对比

2PC
两阶段提交,指的是完成一个分布式事务分为两个阶段,

enter image description here

这个图不是很直观,总之,有两个概念,事务管理器是由数据库如msql实现的XA协议,本地事务管理器通常是由程序实现的, 如java的atomikos。

通俗点将,找个东西做为数据中间件(事务管理器), 监控各个数据库操作的结果. 如果都ok, 那统一发送commit命令.要不然, 统一cancel掉. ok,问题解决了. 这种方案一般被称为两阶段提交(Two-Phase Commit), 简称2PC。

第一阶段,prepare阶段,有协调者发起,顺序对所有事务阻塞的尝试进行提交,比如预扣款,所有参与方都返回成功后,进入第二阶段。
第二阶段commit阶段,事务协调器要求每个数据库提交数据,或者回滚数据。

这个过程中,都是阻塞的,资源锁定的,意味着事务的处理是串行的,整个 系统的可用性降低,处理能力降低,所以2pc的性能很差,是普通数据库事务的10倍。

优点:尽可能地保证了数据的一致性,一次操作要么成功,要么失败,但还是有意外,比如db虽然commit了,但返回的时候网络问题丢失了。

缺点:事务管理器单点问题,角色过于重要。性能太差,不能支持高并发。

TCC
TCC的三个阶段:

  1. Try阶段:尝试执行,完成所有业务检查(一致性),预留必须业务资源(准隔离性)
  2. Confirm阶段:确认执行真正执行业务,不作任何业务检查,只使用Try阶段预留的业务资源,Confirm操作满足幂等性。要求具备幂等设计,Confirm失败后需要进行重试。
  3. Cancel阶段:取消执行,释放Try阶段预留的业务资源 Cancel操作满足幂等性Cancel阶段的异常和Confirm阶段异常处理方案基本上一致。

TCC的核心思想在于牺牲强一致性,不要求事务一次性必须失败或者成功,允许出现异常后,系统进行补偿性操作,即对失败的事务进行恢复。由于不要求强一致性,系统可用性变高,响应时间和处理能力变强,这是与2PC的主要区别,不再锁定资源阻塞系统,提升并发处理能力。但是由此带来的问题是编码复杂,需要编写cancle逻辑,控制并发执行,需要编写补偿job等等。

image.png

你可能感兴趣的:(分布式事务概述)