资料总结 资料总结
首页
go
java
云原生
  • mysql
  • redis
  • MongoDB
  • 设计模式详解
  • 数据结构与算法
  • 前端
  • 项目
  • 理论基础
  • 运营
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

linghui Wu

一只努力学飞的鱼
首页
go
java
云原生
  • mysql
  • redis
  • MongoDB
  • 设计模式详解
  • 数据结构与算法
  • 前端
  • 项目
  • 理论基础
  • 运营
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • java-se

  • jvm

  • mybatis

  • Netty

  • 爬虫 webmagic

  • spring

  • spring-cloud

    • alibaba

      • Nacos使用
      • Sentinel使用
      • skywalking使用
      • 分布式事务理论
        • 两阶段提交协议(2PC)
          • 缺点
        • 三阶段提交协议
        • XA规范
        • 补偿事务(TCC)
          • TCC设计注意事项
          • java实现
        • JTA/XA规范实现
        • 柔性事务TCC
        • 可靠消息最终一致性
          • 本地消息表方案
          • Rocketmq事务消息
        • 最大努力通知
        • 补偿性对账
        • SAGA模式
          • 思考
          • 参考资料
      • Seata使用
      • 分布式Seata原理源码
    • Netflix

    • spring

  • 中间件

  • flowable

  • idea工具

  • maven

  • ms

  • java部署

  • 原生安卓

  • java
  • spring-cloud
  • alibaba
wulinghui
2022-03-29
目录

分布式事务理论

本质上来说,分布式事务就是为了保证不同资源服务器的数据一致性。

# 典型场景

跨库事务、分库分表中的分库、微服务化

# 常见的分布式事务解决方案 (opens new window)

# DTP模型

开源组织定义的(Distributed Transaction Processing,简称DTP)参考模型规范。

5个基本元素: 应用程序AP、资源管理器RM、事务管理器TM、通信资源管理器CRM、通信协议CP。

在DTP本地模型实例中,由AP、RM和TM组成,不需要其他元素。

# 两阶段提交协议(2PC)

  • 在OSI TP标准中提出:在DTP参考模型中,全局事务的提交要使用two-phase commit协议。
  • 只是规范了提交过程的协议。不是在XA规范中提出,但是XA规范对其进行了优化。

将提交(commit)过程划分为2个阶段(Phase):阶段1,CanCommit,TM通知各个RM准备提交它们的事务分支。阶段2,DoCommit,TM根据阶段1各个RM prepare的结果,决定是提交还是回滚事务。

第一阶段准备阶段: 分布式事务的各个参与方都提交自己的本地事务,并且锁定相关的资源。第二阶 段提交阶段:由一个第三方的事务协调者综合处理各方的事务执行情况,通知各个参与方统一进行事务提交或者回退。

# 缺点

  • 同步阻塞问题: 可重复读隔离级别不足以保证分布式事务一致性/隔离性,如果提升的话性能将严重下降;事务长期挂起,也是一个阻塞的问题。
  • 单点故障: 协调者TM是中心化的,其他的RM都依赖于他。 TM挂了,所有的RM会一直阻塞下去。
  • 数据不一致: 在阶段二中,TM发送commit请求给RM时,部分RM没有收到,那一部分会commit、一部分就不会commit;

# 三阶段提交协议

  • 由于二阶段提交存在着诸如同步阻塞、单点问题等缺陷,所以提出了三阶 段提交。
  • 三阶段提交(3PC),是二阶段提交(2PC)的改进版本。

改进点:

在协调者和参与者中都引入超时机制。

在第一阶段和第二阶段中插入一个准备阶段,保证了在最后提交阶段之前各参与节点的状态是一致的。

过程:

CanCommit、PreCommit、 DoCommit

2PC与3PC的区别:

相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会 默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,还是因为网络。

# XA规范

  • XA规范的最主要的作用是,就是定义了RM-TM的交互接口,XA规范除了定义的RM-TM交互的接口(XA Interface)之 外,还对两阶段提交协议进行了优化。

  • 注意: 他只是定义了两阶段提交协议中需要使用到的接口,也就是上述提到 的RM-TM交互的接口,因为两阶段提交过程中的参与方,只有TM和RMs。 (看做是具体的现实接口,但是不仅仅是提交协议还有其他的功能接口;如规范了事务XID的格式)

  • 有3阶段的XA,但是以2pc为主。

# 补偿事务(TCC)

优点:XA两阶段提交资源层面的,而TCC实际上把资源层面二阶段提交上提到了业务层面来实现。有效了的避免了 XA两阶段提交占用资源锁时间过长导致的性能地下问题。 相对于 AT 模式,TCC 模式对业务代码有一定的侵入性,但是 TCC 模式无 AT 模式的全局行锁,TCC 性能会比 AT 模 式高很多。

缺点:主业务服务和从业务服务都需要进行改造,从业务方改造成本更高。原来只需要提供一个接口,现在需要改 造成try、confirm、canel 3个接口,开发成本高。

XA TCC
资源层面的分布式事务 业务层面的分布式事务
强一致性 最终一致性
在两阶段提交的整个过程中,一直会持有资源的锁,性能低 在两阶段提交的整个过程中,不会一直持有资源的锁,性能高
只能再关系型数据库且支持XA中使用 不限数据库、 可以使用其他的nosql、业务都可以支持的

# TCC设计注意事项

要将业务模型分2 阶段设计,保证一阶段 Try 成功的话 二阶段 Confirm 一定能成功。

还有注意网络问题:

  • 防止空回滚 : 出现未收到Try,收到Cancel的情况
  • 防悬挂控制 :分布式事务回滚触发Cancel,之后拥堵的Try到达
  • 幂等控制 : Try,Confirm,Cancel都需要保证幂等性。

根据自身的业务模型进行控制并发(隔离性)

对业务模型进行优化,在业务模型中增加冻结字段,用来表示账户有多少金额处以冻结状态。

# java实现

# JTA/XA规范实现

JTA是java中对XA规范定义的接口。

开源框架Atomikos 、bitronix、narayana等框架

# 柔性事务TCC

开源的TCC框架:

  • Tcc-Transaction
  • Hmily
  • ByteTCC
  • EasyTransaction
  • Seata TCC

# 可靠消息最终一致性

可靠消息最终一致性方案是指当事务发起执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功。

此方案强调的是只要消息发给事务参与方,最终事务要达到一致。

# 本地消息表方案

  • 当前业务操作表 + 日志消息表。 保证了ACID
  • 定时任务扫描日志消息表。往MQ里面发消息
  • 消费消息,实现ack确认和幂等性

# Rocketmq事务消息

在RocketMQ 4.3后实现了完整的事务消息,实际上其实是对本地消息表的一个封装,将本地消息表移动到了MQ 内部,解决Producer端的消息发送与本地事务执行的原子性问题。

  1. Producer发送事务消息
  2. MQ Server回应消息发送成功
  3. Producer执行本地事务
  4. 消息投递,消息commit操作。
  5. 事务回查 :如果执行Producer端本地事务过程中,执行端挂掉,或者超时,MQ Server将会不停的询问同组的其他Producer来获 取事务执行状态。

核心代码

public static void main(String[] args) {
    RocketMQLocalTransactionListener transactionListener // TODO  
    // 设置TransactionListener实现
    producer.setTransactionListener(transactionListener);
    // 发送事务消息
    SendResult sendResult = producer.sendMessageInTransaction(msg, null);
}
// 在这里写本地事务和事务回查。
public interface RocketMQLocalTransactionListener {
    // @return 返回事务状态,COMMIT :提交 ROLLBACK :回滚 UNKNOW :回调
    RocketMQLocalTransactionState executeLocalTransaction(Message msg,Object arg); // 执行本地事务
    RocketMQLocalTransactionState checkLocalTransaction(Message msg); // 事务回查
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 最大努力通知

  • 分布式事务参与方都努力将自己的事务处理结果通知给分布式事务的其他参与方,也就是只保证尽力而为,不保证一定成功。
  • 定位: 最简单的一种柔性事务,是分布式事务中对一致性要求最低的一种。
  • 适用范围 : 一些最终一致性时间敏感度低的业务,且被动方处理结果 不影响主动方的处理结果。
  • 典型的使用场景:如银行通知、 商户通知等。
  • 特点: 不可靠消息,通知N次后不再通 知,允许消息丢失; 定期校对,被动方根据定时策略,向业务活动主动方查询(主动方提供查询接口)恢复丢失的业务消息。
  • 实现功能点: 消息重复通知机制;消息校对机制

# 补偿性对账

  • 不保证事务实时的对齐状态,对于未对齐的事务,事后进行补偿。

    电商调用支付宝的这个场景中,就只能通过定期对账的方式保证在一个账期 内,双方的事务最终是对齐的,至于具体的每一笔订单,只能进行最大努力通知,不保证事务对齐。(类似于上面的消息校对机制)。

# SAGA模式

由分布式事务的各个参与方自己提供正向的提交操作以及逆向的回滚操作。

事务协调者可以在各个参与方提交事务后,随时协调各个事务参与方进行回滚。

一般来说各个参与方做完了自己的事,就会提交事务,不会有长时间事务挂起的情况。

所以适合于事务流程比较长,参与方比较多的场景。

# 思考

  • 一般TCC 再系统中用的比较多,应为可以不限于关系型数据库。 其他的nosql、或者业务都可以支持的。

  • 为什么无论是二阶段提交还是三阶段提交都无法彻底解决分布式的一致性问题??? 因为网络、机器宕机等问题,都会导致某一个节点数据不一致。

  • 最大努力通知与可靠消息最终一致性有什么区别? (opens new window)

    可靠消息最终一致性 最大努力通知
    解决思想不同 由发起方来保证 由接收方来保证
    业务场景不同 关注的是交易过程的事务一致,以异步的方式完成交易 关注的是交易后的通知事务,即将交易结果可靠的通知出去
    技术解决不同 要解决消息从发出到接收的一致性,即消息发出并且被接收到 无法保证消息从发出到接收的一致性,只提供消息接收的可靠性机制。当消息无法被接收方接收时,由接收方主动查询消息。

# 参考资料

什么是分布式事务?2PC、XA、3PC、TCC (opens new window)

可以看到 3PC 的引入并没什么实际突破,而且性能更差了,所以实际只有 2PC 的落地实现。 再提一下,2PC 还是 3PC 都是协议,可以认为是一种指导思想,和真正的落地还是有差别的。

RocketMQ:事务消息 (opens new window)

最大努力通知方案 (opens new window)

最大努力通知,充值场景 (opens new window)

编辑 (opens new window)
上次更新: 2023/01/24, 15:21:15
skywalking使用
Seata使用

← skywalking使用 Seata使用→

最近更新
01
架构升级踩坑之路
02-27
02
总结
02-27
03
语法学习
02-27
更多文章>
| Copyright © 2021-2025 Wu lingui |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式