分布式事务理论与实践

一、产生背景

  1. 业务服务化拆分,原本一个服务能完成的业务操作现在需要跨多个服务;
  2. 分库分表,写操作可能跨多个数据库;

二、理论基础

2.1 2PC协议

角色说明

  • 事务管理器:负责分布式事务的发起与结束,以及失败重试等(事务发起方);
  • 资源管理器:本地事务涉及资源的管理(事务参与方);

协议过程

  • 阶段一: 事务管理器开启分布式事务,通知资源管理器准备资源;(Prepare)
  • 阶段二: 事务管理器判断资源准备情况,如果所有资源管理器都已经准备好资源,则通知资源管理进行提交;否则,进行回滚;(Commit/Rollback)

分布式事务理论与实践_第1张图片

2.2 TCC协议

  TCC协议是服务化的两阶段提交协议,通过改造业务逻辑实现数据最终一致性,原先一个服务接口需要改成try/confirm/cancel三个接口,每个接口作用如下:

  • try:检测预留资源;
  • confirm:真正的业务操作提交;
  • cancel:预留资源释放;

  以减库存场景为例,一阶段try接口的逻辑是检查库存是否充足,如果库存不足则返回错误;如果库存充足,则预扣库存(冻结或锁定的意思);二阶段,confirm接口则真正的扣除库存,cancel接口则是释放预扣的库存。TCC协议是BASE理论很好的说明,保证扣减库存服务可用的前提下,通过增加库存的临时状态,实现库存数据的最终一致性。
分布式事务理论与实践_第2张图片

三、实现方案 — 消息

  消息方案将上下游业务系统解耦,以异步的方式实现业务数据的最终一致性。关键点在于保障上游系统数据变更后,下游系统能够消费到消息,实现方式主要有如下三种。

方案1:本地消息表

执行流程

  1. 首先,执行本地事务,同时插入业务表和消息表;
  2. 其次,实时发送该消息,同时删除对应消息(增加实时性,可能失败);
  3. 最后,通过定时任务兜底,定时从消息表中拉取消息发送,并清理;
  4. 其它业务系统接收到消息后,消费消息,执行本地事务,实现数据的最终一致性;
    分布式事务理论与实践_第3张图片

方案2:binlog消息

执行流程

  1. 业务系统A执行本地事务;
  2. Canal监听数据库变化,采集binlog以MQ消息形式发送出去;
  3. 其它业务系统接收到消息后,消费消息,执行本地事务,实现数据的最终一致性;
    分布式事务理论与实践_第4张图片

方案3:事务消息

正常执行流程

  1. 本地业务逻辑执行前,发送方首先向Broker发送Prepare消息;
  2. Broker接收到消息后,返回ACK;
  3. 发送方执行本地事务;
  4. 如果执行成功发送Commit消息,否则发送Rollback消息;
  5. 如果Broker接收到Commit消息,则将消息投递到Consumer;
  6. 如果Broker接收到Rollback消息,则将删除/废弃消息;

超时回查机制
  为了防止系统宕机或者网络原因导致Broker接收不到Commit/Rollback消息,Broker接收到Prepare消息后会开始倒计时,超时之后会回查Producer查看本地事务的执行状态,返回Commit/Rollback消息。
分布式事务理论与实践_第5张图片

方案说明

注意事项

  1. 幂等性: 如果业务逻辑是非幂等的,比如扣减库存,处理重复消息时需要保障幂等性;
  2. 顺序性: 如果业务逻辑是幂等的,比如更新状态,处理消息时需要注意消息的顺序性,防止乱序导致的数据错误(版本号);

适用场景
  消息方案适用于对业务资源不敏感的场景,比如订单支付成功场景,支付成功后上游支付系统发出消息,下游业务系统消费消息来更新订单状态、消息推送,以及增加积分等;

四、实现方案 — Seata

方案1:AT模式

  AT模式,也叫补偿模式,是一种无业务侵入的分布式事务方案,是对2PC协议的实现,适用于对性能要求不高的中小业务。基本原理是:对数据源进行托管。在一阶段,本地事务执行时,拦截业务SQL,保存SQL执行前后的数据镜像,与业务SQL在同一个本地事务一起执行并提交;在二阶段,如果有本地事务执行失败,需要回滚,TC会回调各业务系统将数据恢复到SQL执行前状态。

执行过程

  1. 业务系统向TC发起分布式事务(这样的角色成为TM);
  2. TM调用下游业务系统,各业务系统本地执行并提交(一阶段本地事务执行成功直接提交);
  3. TM通知TC结束(Commit/Rollback)分布式事务,如果是回滚,TC回调各业务系统,将数据库数据恢复到SQL执行前(二阶段);
    分布式事务理论与实践_第6张图片

一阶段执行过程

  1. 首先,解析SQL语义,提取出关于这条记录的全部信息,包括属于哪张表、查询条件是什么、有哪些字段、这些记录的主键等;
  2. 然后,保存SQL执行前的数据快照到undo log中,便于二阶段的数据回滚;
  3. 执行业务SQL;
  4. 保存SQL执行后的数据快照到redo log中;
  5. 保存表名,主键值到行锁表,防止并发事务;
    分布式事务理论与实践_第7张图片

二阶段执行过程

  1. 对于提交,直接删除中间数据即可;
  2. 对于回滚,先将数据恢复到SQL执行前,然后再删除中间数据即可;
    分布式事务理论与实践_第8张图片

并发控制/隔离性

  • 写写隔离: 为了防止”脏写“,引入全局锁(一阶段本地事务提交前,需要拿到全局锁),某条数据被分布式事务锁定期间,其它分布式事务需要阻塞等待(超时后回滚本地事务);
    分布式事务理论与实践_第9张图片
    分布式事务理论与实践_第10张图片
  • 读写隔离: 默认情况下,AT模式的分布式事务隔离级别是”Read Uncommitted“,存在”脏读“现象,如下图所示。如果业务场景需要Read Committed隔离级别,需要使用SELECT FOR UPDATE语句查询,普通SELECT没有代理。
    分布式事务理论与实践_第11张图片
    分布式事务理论与实践_第12张图片

方案2:TCC模式

  TCC模式是服务层的2PC协议,特点是灵活、能做很多定制和优化,但是对业务有侵入,是微服务架构下最常用的解决方案。TCC的实现分为两方面:一方面,业务服务接口改造成try/confirm/cancel接口(业务侵入性);另一方面,选取合适的事务管理器框架,比如tcc-transaction、seata等;
分布式事务理论与实践_第13张图片
接口设计

  1. 幂等控制: 网络数据包重传、RPC重试等会导致多次调用,try/confirm/cancel接口需要保障幂等性;
  2. 并发控制: 并发事务间预留的资源需要相互隔离;
  3. 允许空回滚: 空回滚是指由于网络超时或服务宕机导致的某个业务服务的try接口未执行,cancel接口被执行的现象。cancel接口设计时需要允许空回滚,即释放预留资源时,发现并没有资源,直接返回即可。
    分布式事务理论与实践_第14张图片
  4. 防悬挂: 悬挂是指由于网络拥堵导致的某个业务服务的cancel接口先执行,try接口后执行的现象。如果try接口执行成功,悬挂会导致预留的资源一直被占用。为了防止悬挂,try接口执行前需要检查当前事务是否已经被回滚。
    分布式事务理论与实践_第15张图片

适用场景
  TCC模式适用于业务资源有限,需要提前预留资源的场景,比如扣减库存、扣减余额等。

参考

  1. “分布式事务一致性” 看这一篇就够了
  2. 分布式事务 Seata TCC 模式深度解析
  3. 蚂蚁金服分布式事务实践解析
  4. Seata官网
  5. 蚂蚁金服大规模分布式事务实践和开源介绍

你可能感兴趣的:(分布式理论)