分布式事务

310 阅读7分钟

分布式事务

1. 分布式事务产生场景

最近学习了分布式事务相关的知识,并在组内进行分享,对分布式事务进行整理总结

1.1 本地事务

指传统的单机数据库事务,更多的是通过关系型数据库来控制事务. 满足数据库事务的四大特性 ACID.

image.png

本地事务主要解决的还是事务的 原子性一致性 ,需要保证从事务开始阶段->事务结束阶段的操作为一个原子操作,整个事务要么全部成功、要么全部失败,且保证数据的一致性。

2.1 分布式事务产生得3种场景

  • 场景一 单体系统访问多个数据库实例, 跨数据库实例 产生分布式事务.

image.png

创建订单扣款流程为例:服务为单体架构,但对数据库进行了分库(订单库/账户库)。如果生成订单成功后,进行扣款就会有很多问题(账户钱不够 / 账户DB崩溃 /网络错误),可能导致数据不一致问题。

  • 场景二 多服务访问同一数据库, 持不同数据库链接 操作产生分布式事务.

image.png

创建订单扣款流程为例:服务为多架构,服务直接通过远程调用。在调用账户服务进行扣款就会有很多问题(账户钱不够 / 账户DB崩溃 /网络错误),极大可能出现数据不一致情况。

  • 场景三 典型的场景微服务架构,微服务之间通过远程调用完成事务.

image.png

创建订单扣款流程为例:整体架构微服务,多数据库多服务实例分布式事务是必须解决的问题

2. CAP理论 & BASE 理论

目前分布式事务理论两个,CAP理论BASE理论

2.1 CAP理论

1998年,加州大学的计算机科学家 Eric Brewer 提出、分布式系统有三个指标

为讲清楚三个指标以 数据库主从同步示例说明:

image.png

  • Consistency (一致性):

在执行写操作后,从任意节点读,读取的数据都是最新状态。

  • Availability (可用性):

任何事务操作都可以得到响应结果,且不会出现响应超时或响应错误。即使数据还没有同步过来,哪怕是旧数据也要返回。

  • Partition tolerance(分区容忍性):

分布式系统各结点部署在不同子网,可能会因网络问题导致结点间通信失败,但仍可对外提供服务。

2.1.1 CAP三种组合

CAP只能两两组合,不能三种共存

image.png

  • AP(可用性、分区容忍):

追求可用性和分区容忍性,放弃强一致性,这是很多分布式系统设计时的选择。 比如:订单退款,今日退款成功,明日账户到账,只要用户可以接受在一定时间内到账即可。

  • CP (强一致性、分区容忍):

追求强一致性和分区容错性,放弃可用性,zookeeper其实就是追求的强一致。 比如:跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。

  • CA(强一致性、可用性):

放弃分区容忍性,即不进行分区,系统将不是一个标准的分布式系统。

2.2 BASE理论

  • 基本可用

出现故障时,允许损失部分可用功能,保证核心功能可用。 如:电商网站交易付款出现问题了,商品依然可以正常浏览

  • 软状态

不要求强一致性,允许系统中存在中间状态(软状态),这个状态不影响系统可用性。 如:订单的“支付中”、“数据同步中”、“处理中”等状态

  • 最终一致

指经过一段时间后,所有节点数据都将会达到一致 如:订单的“支付中”状态,最终变为“支付成功” 或 “支付失败”,但需要一定时间的延迟等待。

3. 分布事务解决方案

以理论为基础,针对不同的分布式场景业界常见的解决方案。

  • 2PC(两阶段提交协议)
  • TCC(Try - Confirm - Cancle)
  • 最大努力通知
  • 可靠消息最终一致性

3.1 两阶段提交2pc

3.1.1 示例

示例:在讲2cp之前我们一起来看一个下单付款的业务。

image.png

该业务存在几个问题:

  1. 库存不够
  2. 账户钱不够
  3. 远程调用网络故障
  4. 商品DB崩溃

问题本质:不知道该业务每个步骤执行的情况?

对上面方案进行改进:

image.png

添加事务管理器(中间协调者): 将各事务执行的情况通知管理器,由管理器根据情况统一通知各事务提交 或者 回滚。

3.1.2 两阶段提交2pc定义

两阶段提交协议将全局事务拆分为两个阶段来执行:

  • 阶段一:准备阶段,各本地事务完成准备工作,但此时事务没有提交。
  • 阶段二:执行阶段,协调者根据阶段一的结果,进行通知提交或者回滚。

image.png

这里大家可能会提出疑问

  1. 预留资源失败:协调者统一进行回滚操作
  2. 二阶段通知失败:协调者可重复通知

3.1.3 两阶段提交2pc优缺点

  • 优点 操作简单, 数据的一致性

  • 缺点 单点故障,协调者挂了, 每个事务会锁定资源性能低(传统)

3.2 TCC(Try - Confirm - Cancle)

3.2.1 TCC定义

阶段补偿方案,柔性事务

  • Try:资源检测 和 预留
  • Confirm:执行业务提交,要求Try成功Confirm必成功。
  • Cancle:预留资源释放。

每个系统都必须开发try / confirm / cancle 三个方法

3.2.2 示例

示例:订单生成业务后进行扣款/减库存/加积分

image.png

第一阶段:在生成订单后,调用库存服务这个时候不是直接减库存,而是冻结库存。

image.png

第二阶段:进行Confirm / cancle,如果第一阶段都成功,那么会调用所有服务的confirm进行业务提交,否则调用Cancle进行释放资源

image.png

问题:

  • 预留资源失败:调用二阶段的Cancle进行释放资源。
  • Confirm/cancle失败:进行重试。
  • Confirm重复执行是否或多扣款:保证接口的幂等性。

3.2.3 优缺点

  • 优点 1. 每个阶段会提交本地事务并释放锁,性能比较高。,2. 不需要等待其它事务执行结果,如其他事务失败,则执行补偿操作。

  • 缺点 1. 业务复杂,实现try、confirm、cancle , 2. 程序员要求高,需要考虑幂等性,重试机制,confirm/cancle在try之前执行处理

3.3 最大努力通知

3.3.1 定义

目标:发起方最大努力将处理结果通知到接收方

image.png

注意点:

  1. 因为接收方可能没收到消息,消息重复通知
  2. 消息校对机制,接收方可主动查询
  3. 接收方需要保证消费幂等性

使用场景:

  1. 对于一致性要求较低的场景可使用
  2. 事务完成的因素在于接收方

3.3.2 示例

image.png

进行业务校对是很重要的

3.4 可靠消息最终一致性

发起方完成本地事务后,一定成功发出消息。 消费者一定能接收消息,并处理事务成功

抛出问题:如何保证本地事务 和 发消息的原子性?

  • 基于本地消息表方案

image.png 将消息持久化到DB, 事务完成的必要因素在于发起方

  • 基于RocketMQ方案 RocketMQ 是一个来自阿里巴巴的分布式消息中间件, 事务消息设计则,就是为了解决消息发送与本地事务执行的原子性问题。

image.png

4. 示例

4.1 几种方案对比

image.png

4.2 示例