本文先讲理论基础,后讲实践。

什么是事务?

一个大的活动,由不通的小活动组成,这些小活动要么全部成功,要么全部失败,叫做事务。
举例:转账,A给B转账100

  1. A帐户-100
  2. B帐户+100
  3. 1和2只能同时成功,或同时失败,整个过程叫事务。

    数据库事务四大特性 ACID

    ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。

    ⑴ 原子性(Atomicity)

    第一个原子性,这个是最简单的。说的是一个事物内所有操作共同组成一个原子包,要么全部成功,要么全部失败。这是最基本的特性,保证了因为一些其他因素导致数据库异常,或者宕机。

    ⑵ 一致性(Consistency)

    原子性中规定方法中的操作都执行或者都不执行,但并没有说要所有操作一起执行(一起更新那就乱套了,要哪个结果?),所以操作的执行也是有先后顺序的,那我们要是在执行一半时查询了数据库,那我们会得到中间的更新的属性?答案是不会的,一致性规定事务提交前后只存在两个状态,提交前的状态和提交后的状态,绝对不会出现中间的状态
    数据库提交事物会有一个过程,如果提交的时候,存在一个时间差,在提交的第一秒,一个删除过程还没完成到了第三秒才完成,会不会第一秒访问的人和第三秒访问的人得到不同的结果?出现不一致,状态的混沌?这就是一致性得保证的只会有前状态和后状态,绝不会出现中间态。

    ⑶ 隔离性(Isolation)

    事物的隔离性,基于原子性和一致性,因为事物是原子化,量子化的,所以,事物可以有多个原子包的形式并发执行,但是,每个事物互不干扰。
    但是,由于多个事物可能操作同一个资源,不同的事物为了保证隔离性,会有很多锁方案,当然这是数据库的实现,他们怎么实现的,我们不必深究。

    ⑷ 持久性(Durability)

    持久性,当一个事物提交之后,数据库状态永远的发生了改变,这个事物只要提交了,哪怕提交后宕机,他也确确实实的提交了,不会出现因为刚刚宕机了而让提交不生效,是要事物提交,他就像洗不掉的纹身,永远的固化了,除非你毁了硬盘。

什么是分布式事务?

简单的说,就是一次大操作由不同小操作组成,这些小操作分布在不同服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败。
你上淘宝买东西,需要先扣钱,然后商品库存-1吧。但扣款和库存分别属于两个服务,这两个服务中间要经过网络、网关、主机等一系列中间层,万一任何一个地方出了问题,比如网络抖动、突发异常等待,都会导致不一致,比如扣款成功了,但是库存没-1,就会出现超卖的现象,而这就是分布式事务需要解决的问题。

分布式事务的应用场景?

  • 1)电商系统中的下单扣库存

电商系统中,订单系统和库存系统是两个系统,一-次下单的操作由两个系统协同完成

  • 2)金融系统中的银行卡充值

在金融系统中通过银行卡向平台充值需要通过银行系统和金融系统协同完成。

  • 3)教育系统中下单选课业务

在线教育系统中,用户购买课程,下单支付成功后学生选课成功,此事务由订单系统和选课系统协同完成。

  • 4) SNS系统的消息发送

在社交系统中发送站内消息同时发送手机短信,- -次消息发送由站内消息系统和手机通信系统协同完成。

CAP理论

如何进行分布式事务控制?CAP理论是分布式事务处理的理论基础
CAP理论是:分布式系统在设计时只能在一致性(Consistency)可用性(Availability)
分区容忍性(Partition Tolerance)中满足两种,无法兼顾三种。

一致性:
服务A、B、C三个结点都存储了用户数据, 三个结点的数据需要保持同一时刻数据一致性。

比如数据库主从同步,主数据库写入后,需等待从数据库也写入成功,才允许查询,写入中过程来查询时先临时锁定直到写入同步完成再响应数据。 强调多分区数据的强一致性。
可用性:
服务A、B、C三个结点,其中一个结点宕机不影响整个集群对外提供服务,如果只有服务A结点,当服务A宕机整个系统将无法提供服务,增加服务B、C是为了保证系统的可用性。

比如数据库主从同步,主数据库写入后,写入中过程来查询直接返回从数据库的旧数据或直接返回空。强系统的强可用性。
分区容忍性:
分区容忍性就是允许系统通过网络协同工作,分区容忍性要解决由于网络分区导致数据的不完整及无法访问等问题。分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

比如数据库主从同步,主从节点之间的网络断开,写入中过程来查询直接报错服务不可用。强调分区之间数据的完整性。**

分布式系统能否兼顾C、A、P?

在保证分区容忍性的前提下一致性和可用性无法兼顾,如果要提高系统的可用性就要增加多个结点,如果要保证数据的一致性就要实现每个结点的数据一致,结点越多可用性越好,但是数据一致性越差。所以,在进行分布式系统设计时,同时满足“一致性”、“可用性”和“分区容忍性”三者是几乎不可能的。

CAP有哪些组合方式?

1、CA:放弃分区容忍性,加强一致性和可用性,关系数据库按照CA进行设计。
2、AP:放弃一致性,加强可用性和分区容忍性,追求最终一致性,很多NoSQL数据库按照AP进行设计。
说明:这里放弃一致性是指放弃强一致性,强一致性就是写入成功立刻要查询出最新数据。追求最终一致性是指允许暂时的数据不一致,只要最终在用户接受的时间内数据 一致即可。
3、CP:放弃可用性,加强一致性和分区容忍性,一些强一致性要求的系统按CP进行设计,比如跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。

说明:由于网络问题的存在CP系统可能会出现待等待超时,如果没有处理超时问题则整理系统会出现阻塞
总结: 在分布式系统设计中AP的应用较多,即保证分区容忍性和可用性,牺牲数据的强一致性(写操作后立刻读取到最新数据),保证数据最终一致性。比如:订单退款,今日退款成功,明日账户到账,只要在预定的用户可以接受的时间内退款事务走完即可。

注意:分布式系统,往往P(分区容忍性)是必要条件,不能因为多节点间的网络故障就导致系统不可用,故只能选择CP(强一致性和分区容忍性)或AP(强可用性和分区容忍性),CP要求用户查询会出现等待阻塞,体验不友好,人们往往都是选择AP,牺牲一部分数据一致性,保证数据最终一致性,强可用性。
**

AP的扩展:Base理论

BASE理论是对CAP理论的延伸,思想是即使无法做到强一致性(CAP的一致性就是强一致性),但可以采用适当的采取弱一致性,即最终一致性。

BASE是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency)

基本可用

基本可用是指分布式系统在出现故障的时候,允许损失部分可用性(例如响应时间、功能上的可用性),允许损失部分可用性。需要注意的是,基本可用绝不等价于系统不可用。
响应时间上的损失:正常情况下搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障(比如系统部分机房发生断电或断网故障),查询结果的响应时间增加到了1~2秒。
功能上的损失:购物网站在购物高峰(如双十一)时,为了保护系统的稳定性,部分消费者可能会被引导到一个降级页面。

软状态

软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据会有多个副本,允许不同副本同步的延时就是软状态的体现。mysql replication的异步复制也是一种体现。

最终一致性

最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。

分布式事务解决方案

基于XA协议的2PC(二阶段提交)

XA是一个分布式事务协议。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚
2阶段提交是分布式事务传统解决方案,现在为止还广泛存在。当一个事务跨越多个节点时,为了保持事务ACID特性,需要引入一个协调者来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

以开会为例:
甲乙丙丁四人要组织一个会议,需要确定会议时间,不妨设甲是协调者,乙丙丁是参与者。
投票阶段:

  1. 甲发邮件给乙丙丁,周二十点开会是否有时间;
  2. 丁回复有时间;
  3. 乙回复有时间;
  4. 丙迟迟不回复,此时对于这个活动,甲乙丙均处于阻塞状态,算法无法继续进行;
  5. 丙回复有时间(或者没有时间);

提交阶段:

  1. 协调者甲将收集到的结果反馈给乙丙丁(什么时候反馈,以及反馈结果如何,在此例中取决于丙的时间与决定);
  2. 乙收到;
  3. 丙收到;
  4. 丁收到;

缺点:不仅要锁住参与者的所有资源,而且要锁住协调者资源,开销大。一句话总结就是:2PC效率很低,对高并发很不友好

3PC(三阶段提交)

与两阶段提交不同的是,三阶段提交有两个改动点。

  • 1、引入超时机制。同时在协调者和参与者中都引入超时机制。
  • 2、在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

    阶段一:CanCommit

    事务询问 执行者向所有参与者发送CanCommit请求,等待所有参与者的响应
    参与者反馈响应 参与者节点若认为自身可以完成事务,返回Yes;反之,返回No

    阶段二:PreCommit

    若所有参与者反馈的结果都是Yes响应,那么进行事务预提交
    若任意一个参与者反馈的结果是No响应,或者在等待超时之后,那么执行事务中断

    阶段三:doCommit

    该阶段可能存在两种情况,执行事务的提交和中断事务
    若执行者接受到所有参与的Ack响应,那么执行事务提交
    如果有任意一个参与者反馈No响应,或者在等待超时之后,执行中断事务

    TCC(事务补偿)

    所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,如果更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是通过代码人为实现了两阶段提交,不同的业务场景所写的代码都不一样,复杂度也不一样,因此,这种模式并不能很好地被复用。

  • LCN框架官网地址:http://www.txlcn.org/zh-cn/

LCN分布式事务框架的核心功能是对本地事务的协调控制,框架本身并不创建事务,只是对本地事务做协调控制。LCN框架主要是为微服务框架提供分布式事务的支持,在微服务框架上做了进一步的事务机制优化。

柔性事务

所谓柔性事务是相对强制锁表的刚性事务而言。流程如下:服务器A的事务如果执行顺利,那么事务A就先行提交,如果事务B也执行顺利,则事务B也提交,整个事务就算完成。但是如果事务B执行失败,事务B本身回滚,这时事务A已经被提交,所以需要执行一个补偿操作,将已经提交的事务A执行的操作作反操作,恢复到未执行前事务A的状态。

缺点是业务侵入性太强,还要补偿操作,缺乏普遍性,没法大规模推广。

消息最终一致性解决方案之RocketMQ

采用最终一致性原理。
需要保证以下三要素:
1、确认生产者一定要将数据投递到MQ服务器中(采用MQ消息确认机制)
2、MQ消费者消息能够正确消费消息,采用手动ACK模式(注意重试幂等性问题)
3、如何保证第一个事务先执行,采用补偿机制,在创建一个补单消费者进行监听,如果订
单没有创建成功,进行补单。(如果第一个事务中出错,补单消费者会在重新执行一次第一个
事务,例如第一个事务是添加订单表,如果失败在补单的时候重新生成订单记录,由于订单号
唯一,所以不会重复)

经典案例,以目前流行点外卖的案例,用户下单后,调用订单服务,让后订单服务调用派单系
统通知送外卖人员送单,这时候订单系统与派单系统采用MQ异步通讯。

MQ解决分布式事务一致性
案例中 订单表 和 派单表必须一致!