分布式事务解析
2021-03-26 11:08:39 110 举报
AI智能生成
分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的节点上,且每个节点都具有独立处理事务的能力。简单来说,分布式事务就是为了保证在跨越多个数据库或服务器上的操作都能够成功或者全部失败而进行的事务管理。它需要保证所有节点的数据一致性,即使在网络故障、系统崩溃等异常情况下也能保持数据的完整性和一致性。为了实现这一目标,分布式事务采用了一些特定的协议和技术,如两阶段提交协议(2PC)、三阶段提交协议(3PC)等。
作者其他创作
大纲/内容
理论
CAP
三要素
一致性(Consistency)
分布式环境下,多个节点的数据是否强一致。
可用性(Availability)
分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。
分区容错性(Partition Tolerance)
特指对网络分区的容忍性。
系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择
系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择
3 个要素最多只能同时满足两个
AP
Cassandra
Dynamo
CP
HBase
MongoDB
BASE
基本可用(Basically Available)
指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用;
软状态(Soft state)
指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性;
最终一致性(Eventual consistency)
指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态;
原子性(A)与持久性(D)必须根本保障;
为了可用性、性能与降级服务的需要,只有降低一致性( C ) 与 隔离性( I ) 的要求;
一致性模型
强一致性
数据更新成功后,任意时刻所有副本中的数据都是一致的,一般采用同步的方式实现。
弱一致性
数据更新成功后,系统不承诺立即可以读到最新写入的值,也不承诺具体多久之后可以读到。
最终一致性
弱一致性的一种形式,数据更新成功后,系统不承诺立即可以返回最新写入的值,但是保证最终会返回上一次更新操作的值。
分布式系统数据的强一致性、弱一致性和最终一致性可以通过 Quorum NRW 算法分析。
解决方案
典型方案
两阶段提交
(强一致)
(强一致)
基于XA协议实现
需要独立的事务管理器来管理所有参与者
执行
第一阶段是表决阶段,所有参与者都将本事务能否成功的信息反馈发给协调者;
第二阶段是执行阶段,协调者根据所有参与者的反馈,通知所有参与者,步调一致地在所有分支上提交或者回滚;
缺点
单节点问题
事务管理器在整个流程中扮演的角色很关键,如果其宕机;
比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
同步阻塞
在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源
数据不一致
两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能
比如:在第二阶段中,假设协调者发出了事务 Commit 的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了 Commit 操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
比如:在第二阶段中,假设协调者发出了事务 Commit 的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了 Commit 操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
优点
总的来说,XA 协议比较简单,成本较低
TCC补偿模式
(强一致性)
(强一致性)
核心思想
针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。
三个阶段
(默认只有try-confirm两个阶段)
(默认只有try-confirm两个阶段)
1.Try 阶段主要是对业务系统做检测及资源预留
2.Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。
即:只要Try成功,Confirm一定成功。
即:只要Try成功,Confirm一定成功。
3.Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
优点
跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些
缺点
在2,3步中都有可能失败。
TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。
本地消息表
(最终一致性)
(最终一致性)
核心思想
将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等的。
本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。
理论
在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中;
之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发;
消息消费方处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作;
优点
一种非常经典的实现,避免了分布式事务,实现了最终一致性。
缺点
消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。
核心问题
第二阶段的重试和幂等执行。失败后重试,这是一种补偿机制,它是能保证系统最终一致的关键流程。
与常规MQ对比
常规MQ队列消息的处理流程无法实现消息发送一致性,因此直接使用现成的MQ中间件产品无法实现可靠消息最终一致性的分布式事务解决方案
即消息产生(数据库事务)和MQ的发送(无法通过数据库事务管理)无法通过事务做到一致性
消息发送一致性
是指产生消息的业务动作与消息发送的一致。也就是说,如果业务操作成功,那么由这个业务操作所产生的消息一定要成功投递出去(一般是发送到kafka、rocketmq、rabbitmq等消息中间件中),否则就丢消息。
可靠消息最终一致(常用)
不要用本地的消息表了,直接基于MQ来实现事务。比如阿里的RocketMQ就支持消息事务。
流程
1.A系统先发送一个prepared消息到mq,如果这个prepared消息发送失败那么就直接取消操作别执行了
2.如果这个消息发送成功过了,那么接着执行本地事务,如果成功就告诉mq发送确认消息,如果失败就告诉mq回滚消息
3.如果发送了确认消息,那么此时B系统会接收到确认消息,然后执行本地的事务
4.mq会自动定时轮询所有prepared消息回调你的接口,问你,这个消息是不是本地事务处理失败了,所有没发送确认消息?那是继续重试还是回滚?一般来说这里你就可以查下数据库看之前本地事务是否执行,如果回滚了,那么这里也回滚吧。这个就是避免可能本地事务执行成功了,别确认消息发送失败了。
5.这个方案里,要是系统B的事务失败了咋办?重试咯,自动不断重试直到成功,如果实在是不行,要么就是针对重要的资金类业务进行回滚,比如B系统本地回滚后,想办法通知系统A也回滚;或者是发送报警由人工来手工回滚和补偿
最大努力通知
业务发起方将协调服务的消息发送到MQ,下游服务接收此消息,如果处理失败,将进行重试,重试N次后依然失败,将不进行重试,放弃处理,这个应用场景要求对事物性要求不高的地方。
解决方案分类
两阶段
XA协议、TCC
补偿型
saga
异步确保型
本地消息表
最大努力通知型
本地消息表、可靠消息最终一致
服务模式
可查询操作
幂等操作
TCC操作
可补偿操作
框架服务
seata
AT模式
两阶段提交模式(非数据库支持的两阶段提交)
1.第一阶段,业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。(不锁数据库,不阻塞)
2.二阶段:
提交异步化,非常快速地完成。
回滚通过一阶段的回滚日志进行反向补偿。
提交异步化,非常快速地完成。
回滚通过一阶段的回滚日志进行反向补偿。
undo_log日志回滚原理
记录数据修改前后镜像,回滚时根据前后镜像与当前镜像(实时数据)决定回滚;
写隔离
一阶段本地事务提交前,需要确保先拿到 全局锁 。
拿不到 全局锁 ,不能提交本地事务。
拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
拿不到 全局锁 ,不能提交本地事务。
拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
读隔离
在数据库本地事务隔离级别读已提交(Read Committed) 或以上的基础上;
Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
必需要求全局的读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。
缺点
数据锁时间长,不适合高并发
一旦有别的方式修改了数据(不使用全局事务锁的方式,eg:客户端手动操作SQL),而又正好需要回滚数据,会导致混滚失败(undo_log中记录镜像不一致)
XA模式(标准的二次提交)
以 XA 协议的机制来管理分支事务的一种 事务模式。
流程
执行阶段:
可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)
可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)
完成阶段:
分支提交:执行 XA 分支的 commit
分支回滚:执行 XA 分支的 rollback
分支提交:执行 XA 分支的 commit
分支回滚:执行 XA 分支的 rollback
存在的问题
在第二阶段中,如果协调器和业务系统都挂了,将导致部分成功,部分失败
TCC模式
两阶段模式(非XA两阶段体提交模式)
一阶段 prepare 行为
二阶段 commit 或 rollback 行为
二阶段 commit 或 rollback 行为
调用 自定义 的 prepare 逻辑。
调用自定义的 commit 逻辑 OR 调用自定义的 rollback 逻辑。
缺点
开发任务大,每一个业务操作,都需要3个自定义方法处理,无法复用
实现方式举例
需要操作的目标字段,都要添加一个相关的冻结字段,try操作是操作冻结字段,cc操作时,将冻结的数值更新到目标字段。
saga模式(业务补偿方式的长事务解决方案)
每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者
一阶段正向服务和二阶段补偿服务都由业务开发实现
一阶段正向服务和二阶段补偿服务都由业务开发实现
业务场景
业务流程长、业务流程多
参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
优势
一阶段提交本地事务,无锁,高性能
事件驱动架构,参与者可异步执行,高吞吐
补偿服务易于实现
事件驱动架构,参与者可异步执行,高吞吐
补偿服务易于实现
缺点
不保证隔离性
每个业务独立提交事务
TX-LCN
锁定事务单元(lock)
确认事务模块状态(confirm)
通知事务(notify)
确认事务模块状态(confirm)
通知事务(notify)
LCN模式
TCC模式
TXC模式
hmily
(TCC模式)
(TCC模式)
ByteTCC
(TCC模式)
(TCC模式)
TCC-transaction
0 条评论
下一页