• 分布式事务详解


    最近很多公司都是在使用分布式架构,比如dubbo+zookeeper的或者是springcloud全家桶的,不管是什么技术,一般都会涉及到分布式事务.今天我们来谈谈分布式事务.

    首先什么是分布式

    :图片就是百度知道里面的:
    在这里插入图片描述

    个人理解分布式简单的说就是原本由一台机子完成,现在由很多机子一起完成.得到结果是一个整体.好比以前单体项目就是部署在一个tomcat容器里面,放在一台电脑上面,连接一个数据库,分布式架构就是项目部署在很多tomcat上面,tomcat运行在很多台电脑上面,可能他们连接的很多数据库,也有可能连接的同一台,然后项目的速度更快更好.详见:趣谈分布式架构

    那什么是事务:

    事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。简单来说就是全部成功,要么全部失败.事务有四大特性,就是ACID,原子性(Atomicity),一致性(Consistency),隔离性(Isolation),持久性(Durability)----mysql的Innodb支持事务.

    那么什么是分布式事务呢?

    在这里插入图片描述
    自己简单的理解就是不同数据库或者不同的数据库连接所进行的操作,就会产生分布式事务的问题.而分布式事务就是为了保证在不同的数据库或者不同的数据库连接所进行的操作要么全部成功要么全部失败,保证数据库的的数据一致性。

    CAP理论

    CAP 定理,又被叫作布鲁尔定理。
    C (一致性):对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的

    A (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回 50,而不是返回 40。

    P (分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。熟悉 CAP 的人都知道,三者不能共有,如果感兴趣可以搜索 CAP 的证明,在分布式系统中,网络无法 100% 可靠,分区其实是一个必然现象。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    个人总结一下,cap定理就是讲了在分布式环境中,分区容错性比较重要,又由于三者不可兼得,所以,分布式事务的主要解决方法都是CP或者AP.

    BASE理论

    BASE理论 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写,是对 CAP 中 AP 的一个扩展。BASE 和 ACID 是相反的,它完全不同于 ACID 的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。

    出现了分布式事务那就要解决,提供了几种解决方案:

    X/Open DTP

    DTP 是 X/Open 组织定义的一套分布式事务的标准,在 DTP 事务模型中,定义了三个角色:AP、RM 和 TM。XA是由X/Open组织提出的分布式事务的规范。XA规范主要定义了 TM 和 RM 之间的接口。主流的关系型数据库产品都是实现了XA接口的。
    在这里插入图片描述
    在 Java 中对 XA 标准的实现是 JTA,比较有名的 JTA 实现框架就是 JOTM 和 Atomikos。

    2PC

    2PC 就是基于 XA,协调 TM 和 RM 的一种机制。分为两个阶段:
    第一个阶段:
    发出“准备”命令,所有事务参与者接受指令后进行资源准备,锁准备,undo log准备。如果都返回“准备成功”,如果不能执行,返回终止。
    第二个阶段
    协调者接受到第一个阶段的回复
    如果都是ok,则发出“提交”命令,所有参与者进行commit操作。如果都成功,随后 RM 给 TM 一个反馈的 Ack 消息,则事务结束,如果有失败情况,协调者发出“回滚”命令,所有事务参与者利用undo log进行回滚(这个在2PC不存在)。J2EE对JTA就是两阶段提交的实现。
    如果有不ok,则发出撤销,所有事物撤销本地资源的锁定等操作
    在这里插入图片描述
    优点:

    较强的一致性,适合于对数据一致性要求比较高对场景,当然并不是100%一致性;

    缺点:

    1. 性能问题,整个过程耗时过程,锁定资源时间过长,同步阻塞(准备阶段回复后,一直等待协调者调用commit或者rollback),CAP中达到了CP,牺牲了可用性,不适合高并发场景 协调者可能存在单点故障

    2. 数据不一致:比如在第二阶段,当 TM 向 所有 RM 发送 commit 请求的时候,假如在这个过程中发生了比如网络问题造成只有部分 RM 收到了 commit 请求,那么会造成 RM 之间数据不一致。

    3. Commit阶段可能存在部分成功,部分失败情况,并没有提及是否rollback

    4. 单点问题:TM 在整个流程中的作用非常关键,一旦 TM 宕机,所有的 RM 都会被阻塞。

    5. 容错问题:其实这个也可以结合上面的“单点问题”来说。如果在第一阶段中,由于某些原因造成部分 RM 未及时给 TM 返回消息,虽然此时 TM 可以设置某些超时机制,但是是否有必要因此而造成所有的 RM 的事务回滚。总的来说,2PC 没有比较完善的容错机制。

    开源实现:
    Spring jta
    Bitronix

    3PC三阶段提交(非阻塞,引入超时和准备阶段)

    3PC 属于 2PC 的改进版,将 2PC 的第一阶段又拆分成了两个阶段。形成了 CanCommit、PreCommit、DoCommit 三个阶段。在第一阶段,TM 只是询问所有参与者是否可以执行事务操作,并不在本阶段执行事务操作。当 TM 收到所有的 RM 都返回“Yes”时,在第二阶段才执行事务操作,然后在第三阶段执行 commit 或者 rollback。
    在这里插入图片描述
    个人理解:

    3PC解决了2PC的很多不足,比如如果协调者或者执行者出现网络问题,接收不到doCommit请求,超时默认执行的是doCmmit,虽然解决了2PC部分问题,但是如果接收不到TM的rollback请求,部分网络问题,导致部分没有收到rollback请求,而其他的机器进行了回滚操作,超时的进行了提交,这样就会出现数据不一致问题.

    TCC模式-本质也是2PC

    TCC 是三个单词的首字母,Try-Confirm-Cancel。
    模式本质也是2PC,只是TCC在应用层控制,数据库只是负责第一个阶段。XA在数据库层控制两阶段提交。
    TCC 有两个阶段三种操作:
    在这里插入图片描述
    严格遵守ACID的分布式事务我们称为刚性事务,而遵循BASE理论(基本可用:在故障出现时保证核心功能可用,软状态:允许中间状态出现,最终一致性:不要求分布式事务打成中时间点数据都是一致性的,但是保证达到某个时间点后,数据就处于了一致性了)的事务我们称为柔性事务,其中TCC编程模式就属于柔性事务。

    TCC是对二阶段的一个改进,try阶段通过预留资源的方式避免了同步阻塞资源的情况,但是TCC编程需要业务自己实现try,confirm,cancle方法,对业务入侵太大,实现起来也比较复杂。

    分布式事务的基本原理本质上都是两阶段提交协议(2PC),TCC (try-confirm-cancel)其实也是一种 2PC,只不过 TCC 规定了在服务层面实现的具体细节,即参与分布式事务的服务方和调用方至少要实现三个方法:try 方法、confirm 方法、cancel 方法。

    Saga

    github有详解:https://github.com/eventuate-tram/eventuate-tram-sagas
    前面介绍的几种分布式事务解决方案中,XA 是一种最初的解决方案;基于可靠消息的最终一致性和最大努力通知属于一类,都是基于消息驱动;TCC 是单独的一类,在分布式事务的解决方案中,还有一类,就是基于事件溯源(Event Sourcing)的 Saga 事务模型。

    这里先简单介绍一下事件溯源模式。在事件溯源模式中,事件要作为数据保存,会有一个统一的事件管理器 Event Store(对外提供接口),所有的数据更新操作都要通过 Event Store,数据库中的数据的当前状态由事件聚合产生。
    在这里插入图片描述
    用户做了一系列的操作,触发了一系列的事件,经过事件聚合,最终在数据库中,用户的购物车中只有一个 B 商品。
    在这里插入图片描述
    一个 Saga 事务由多个本地事务所组成, 每个本地事务有相应的执行模块和补偿模块,当 Saga 事务中的任意一个本地事务出错了,可以通过调用相关事务对应的补偿方法恢复,达到事务的最终一致性。在 Saga 中,一个事件只能处理一个服务的数据(所以事件的粒度设计是一个要注意的地方),由于可能会有重试的操作,故每次事件处理必须实现幂等。

    幂等就是如果多次处理数据,数据的结果是一样的,好比做支付的朋友应该知道,如果第三方回调过来,我们需要扣除我们服务器上的金额,有时候处理比较慢,第三方又发送一条消息,这时候肯定不能重复扣费,就应该根据订单状态或者其他标识来进行处理,使第二次请求直接返回.避免重复扣费.

    Saga 有两种执行执行策略:超时重复策略和可交换补偿策略。超时重复策略就是说如果事务执行顺序为 T1->T2->T3,中间某个环节出了问题,就不断重试,一般这种策略适用于肯定会成功的场景;可交换补偿策略指的就是如果中间某个环节出了问题,达到了补偿要求后相应的执行补偿操作。理论上补偿操作是不会失败的,如果由于某些原因失败了,可以采取人工干预等措施。-tram/eventuate-tram-sagas
    在这里插入图片描述
    Saga 有一个最大的问题就是事务之间没有隔离性,因为 Saga 并没有锁住资源。目前 Saga 实现的比较好的有华为的 ServiceComb,ServiceComb 解决隔离性问题的思路也是参考了 TCC 的解决方案,从业务层面入手加入 Session 以及锁的机制来保证能够串行化操作资源。也可以在业务层面通过预先冻结资金的方式隔离这部分资源, 最后在业务操作的过程中可以通过及时读取当前状态的方式获取到最新的更新。

    项目中,应该尽量避免分布式事务,

    转载:https://www.jianshu.com/p/16b1baf015e8
    转载:https://mp.weixin.qq.com/s/-LqQlhGfLOLSGlSQaXWbrA
    转载:https://blog.csdn.net/hanruikai/article/details/82659223

    世界上所有的不公平都是由于当事人能力不足造成的.
  • 相关阅读:
    使用_Capistrano_进行自动化部署(2)
    使用 Capistrano 进行自动化部署
    Zend_Framework_1 框架是如何被启动的?
    PHP新版本变化
    Phpstorm 无法自动断点 Exception
    理解希尔排序
    C# Thread 线程
    Unity 依赖注入容器的AOP扩展
    C# 面向切面编程 AOP
    C# 表达式树 Expression
  • 原文地址:https://www.cnblogs.com/javayida/p/13347021.html
Copyright © 2020-2023  润新知