提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
一、引入分布式事物概念
我们常用单节点事物无法满足在分布式系统场景下的需求,因为分布式系统中运行的事物,由多个本地事物组成。在分布式场景下,事物可能来自与不同的系统,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据存储的数据一致性。
导致传统单节点事物失效场景
1.1、服务SOA
所谓的SOA化,就是业务的服务化。不同的服务有着属于自己的数据库数据,但是业务需求在同一时间或者是同一个操作下,完成对两个服务对应数据库进行操作。在操作过程,某一个服务宕机后执行的回滚操作,但是另一个服务接收不到任何信息,仍正常执行。
1.2、分别库分表
当数据库单表一年产生的数据超过1000W,那么就要考虑分库分表。这时候,如果一个操作既访问第1个数据库库,又访问第2个数据库,而且要保证数据的一致性,那么就要用到分布式事务。
1.3、多个服务共享
存在多个服务在进行操作时,共享使用同一个数据库数据
二、上理论
随着互联网高速发展应运而生的,传统的数据库的ACID(原子、一致、隔离、持久)四大特性,已经无法满足我们分布式事务,此时针对分布式系统产生新的理论概念
2.1、CAP理论
一致性(Consisitency)、可用性(Availability)、分区容错性(Partition tolerance )
-
一致性:写操作完成后,读操作一定是读的最新的数据,尽管数据分布在多个节点,也要保证的读取的内容是最新的
-
可用性:指任何事物操作都可以得到响应结果,且不会出现响应超时或响应错误
-
分区容错性:通常分布式系统的各个节点部署在不同的子网,这就是网络分区,不可避免的会出现由于网络问题而导致点之间通信失败,此时仍可对外提供服务,这就分区容忍性
其中一致性可能存在对资源的暂时锁定来进行数据同步,这样做的理由是必须读取到的最新的数据,如果期间出现问题,也不会读取到的旧数据
而可用性是只要的能够读取到的数据就可以,不管是否是新数据,这样做的是不会出现响应超时或者是相应错误,来保证可用性.
两者存在矛盾,所以在CAP理论中只能满足两个,
在分布式系统中,网络无法100%可靠,分区其实是一个必然现象,如果我们选择了CA而放弃了P,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求,但是A又不允许,所以分布式系统理论上不可能选择CA架构,只能选择CP或者AP架构。
2.2、BASE理论
基本可用(Basically Available)、软状态(Soft state)、最终一致性 (Eventually consistent)
base理论是对CAP中的AP进行的一个扩展
-
基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。
-
软状态:允许系统中存在中间状态,这个状态不影响系统可用性,这里指的是CAP中的不一致。
-
最终一致:最终一致是指经过一段时间后,所有节点数据都将会达到一致。
2.3、2PC
2PC具有普适性,目前绝大多数分布式事务解决方案都是以两阶段提交协议2PC为基础的。
顾名思义,2PC分为两个阶段:Prepare和Commit。
2.3.1、Prepare-准备
-
询问:协调者向所有参与者发送事务请求,询问是否可执行事务操作,然后等待各个参与者的响应。
-
执行:各个参与者接收到协调者事务请求后,执行事务操作(例如更新一个关系型数据库表中的记录)并将Undo和Redo信息记录事务日志中。
-
响应:如果参与者成功执行了事务并写入Undo和Redo信息,则向协调者返回YES响应,否则返回NO响应。当然,参与者也可能宕机,从而不会返回响应。
2.3.2、Commit-成功
-
commit请求:协调者向所有参与者发送Commit请求。
-
事务提交:参与者收到Commit请求后,执行事务提交,提交完成后释放事务执行期占用的所有资源。
-
反馈结果:参与者执行事务提交后向协调者发送Ack响应。
-
完成事务:接收到所有参与者的Ack响应后,完成事务提交。
2.3.3、Commit-失败
-
rollback请求:协调者向所有参与者发送Rallback请求。
-
事务回滚:参与者收到Rallback请求后,使用Prepare阶段的Undo日志执行事务回滚,完成后释放事务执行期占用的所有资源。
-
反馈结果:参与者执行事务回滚后向协调者发送Ack响应。
-
回滚事务:接收到所有参与者的Ack响应后,完成事务回滚。
2.3.4、存在问题
-
性能问题:在事务执行过程中,各个节点占用着数据库资源,只有当所有节点准备完毕,事务协调者才会通知提交,参与者提交后释放资源。
-
协调者单点故障问题:事务协调者是整个模型中的核心,一旦事务协调者节点挂掉,参与者收不到提交或是回滚通知,参与者会一直处于中间状态无法完成事务。
-
丢失消息导致的不一致问题。:在第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致
-
没有完善的容错机制:太过保守 ,任意一个节点失败就会导致整个事务失败,没有完善的容错机制。
三、分布式事物解决方案
针对不同的场景,有着不同的解决方案,常用的:
- seata阿里分布式事务框架。。。代表:全局事务
- 消息队列 。。。。。。。。。。代表:基于可靠消息
- saga。。。。。。。。。。。。代表:最大努力通知
- XA。。。。。。。。。。。。。代表:TCC
以上方案都存在同一个特点:都是 两阶段(2PC),在上文有解释到
3.1、seata-AT
( Auto Transaction)是一种 无侵入 的方案,阿里提供的seata框架主推的一中模式,在该模式下,会用sql作为第一阶段,框架会自动生成事物的二阶段提交和回滚操作。
-
一阶段:在一阶段,Seata会拦截业务sql,首先解析sql语义,找到业务sql要更新的业务数据,在业务数据被更新之前,将其保存成before image,然后执行业务sql更新业务数据,在业务数据更新之后,再将其保存成after image,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。
-
二阶段提交:二阶段如果是提交的话,因为业务sql在一阶段已经提交至数据库,所以Seata框架只需将一阶段保存的快照数据和行锁删除,完成数据清理即可。
-
二阶段回滚:二阶段如果是回滚的话,Seata就需要回滚一阶段已执行的业务sql,还原业务数据。回滚方式便是用before image 还原业务数据,但在还原前要首先校验脏写,对比数据库当前业务数据和after image,如果两份数据完全一致就说明没有脏写,可以还原业务数据。如果不一致,就说明有脏写,出现脏写就需要转人工处理。
3.2、消息队列
在实际系统的开发过程中,还可以采用MQ特性来实现分布式事物方案,服务间的调用是异步的操作。实现最终一致性方案
发送方
- 发送方需要发送一条消息给可靠消息服务。就是是对下游服务一个接口的调用,里面包含了对应的一些请求参数,并且保证可以正常的投入到消息队列中。
- 可靠消息服务就得把这条消息存储到自己的数据库中,状态为“待确认”。
- 发送方就可以执行自己本地的数据库操作,根据自己的执行结果,再次调用可靠消息服务的接口
- 如果本地数据库操作执行成功了,那么就找可靠消息服务确认那条消息。如果本地数据库操作失败了,那么就找可靠消息服务删除那条消息。
- 此时如果是确认消息,那么可靠消息服务就把数据库里的消息状态更新为“已发送”,同时将消息发送给 MQ。
接收方
- 接收方一直等着从 MQ 消费消息好了,如果消费到了消息,那么就操作自己本地数据库
3.3、最大努力通知
事务发起方会通过一定的机制下将业务处理的结果尽可能的通知下游业务接收方
类似常见的充值系统
- 用户充值完成之后,充值中心需要回调业务系统告知用户充值的结果
- 若当次通知失败或未收到业务系统的正常响应的时候应该继续通知
- 业务系统在未接受到通知的时候,充值系统也应该提供查询接口供业务主动查询
核心
- 消息重复通知的机制: 对方无应答需要重试机制重复通知
- 消息校对机制: 最大努力通知不是无限次的一直通知,当通知次数达到阈值之后将不会再继续通知,此时需要上游服务提供一个能力供下游业务系统查询消息
实现
- 利用MQ的ACK机制由MQ向接收方发送通知,接收方接收到消息之后,业务处理完成回复ACK,接收方接收到消息之后,业务处理完成回复ACK
3.4、TCC
TCC模式需要用户根据自己的业务场景实现Try、Confirm和Cancel三个操作。事务发起方在一阶段执行Try方法,在二阶段提交执行Confirm方法,二阶段回滚执行Cancel方法。
- Try:尝试执行业务,完成所有业务检查(一致性),预留必要的业务资源(准隔离性,中间状态)
- Confirm:确认执行业务,不再做业务检查。只使用Try阶段预留的业务资源,Confirm操作满足幂等性。
- Cancel:取消执行业务,释放Try阶段预留业务资源。
优点:在整个过程中基本没有锁,性能更强。
缺点: 侵入性比较强,并且需要用户自己实现相关事务控制逻辑。