分布式系列第二弹:分布式事务!

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 分布式系列第二弹:分布式事务!

之前文章:分布式系列第一弹:分布式一致性!

柔性事务

柔性事务主要分为补偿型和通知型。

补偿型事务分:TCC、Saga。

通知型事务分:MQ事务消息、最⼤努⼒通知型。

补偿型事务都是同步的,通知型事务都是异步的。

二阶段提交

二阶段提交协议(2PC)

二阶段提交算法的成立基于以下假设:

在该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Participants),且节点之间可以进行网络通信;

所有节点都采用预写式日志,日志被写入后被保存在可靠的存储设备上,即使节点损坏也不会导致日志数据的丢失;

所有节点不会永久性损坏,即使损坏后仍然可以恢复。

两阶段提交中的两个阶段,指的是 Commit-Request 阶段和 Commit 阶段,两阶段提交的流程如下:

提交请求阶段(Commit-Request)

在提交请求阶段,协调者将通知事务参与者准备提交事务,然后进入表决过程。

在表决过程中,参与者将告知协调者自己的决策:

  • 同意(事务参与者本地事务执行成功)或取消(本地事务执行故障),在第一阶段,参与节点并没有进行Commit操作。

提交阶段(Commit)

在提交阶段,协调者将基于第一个阶段的投票结果进行决策:

提交或取消这个事务,这个结果的处理和前面基于半数以上投票的一致性算法不同,必须当且仅当所有的参与者同意提交,协调者才会通知各个参与者提交事务,否则协调者将通知各个参与者取消事务。

参与者在接收到协调者发来的消息后将执行对应的操作,也就是本地 Commit 或者 Rollback。

两阶段提交存在的问题:

资源被同步阻塞:

  • 在执行过程中,所有参与节点都是事务独占状态,当参与者占有公共资源时,那么第三方节点访问公共资源会被阻塞。

协调者可能出现单点故障:

  • 一旦协调者发生故障,参与者会一直阻塞下去。

在 Commit 阶段出现数据不一致:

在第二阶段中,假设协调者发出了事务 Commit 的通知,但是由于网络问题该通知仅被一部分参与者所收到并执行 Commit,其余的参与者没有收到通知,一直处于阻塞状态,那么,这段时间就产生了数据的不一致性。

三阶段提交

三阶段提交协议(3PC)

为了解决二阶段协议中的同步阻塞等问题,三阶段提交协议在协调者和参与者中都引入了超时机制,并且把两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。

三阶段中的 Three Phase 分别为 CanCommit、PreCommit、DoCommit 阶段。

三阶段提交做了哪些改进:

引入超时机制:

在 2PC 中,只有协调者拥有超时机制,如果在一定时间内没有收到参与者的消息则默认失败,3PC 同时在协调者和参与者中都引入超时机制。

添加预提交阶段:

在 2PC 的准备阶段和提交阶段之间,插入一个准备阶段,使 3PC 拥有 CanCommit、PreCommit、DoCommit 三个阶段,PreCommit 是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。

三阶段提交协议存在的问题

在阶段三中,如果参与者接收到了 PreCommit 消息后,出现了不能与协调者正常通信的问题,在这种情况下,参与者依然会进行事务的提交,这就出现了数据的不一致性。

MQ消息事务

方案一:依靠MQ的事务消息机制来实现投递消息和参与者⾃身本地事务的⼀致性保障。

消息的可靠发送由发送端 Producer进行保证(消费端无需考虑),可靠发送消息的步骤如下:

  • 发送一个事务消息,RocketMQ将消息状态标记为Prepared,注意此时这条消息消费者是无法消费到的。
  • 执行业务代码逻辑,可能是一个本地数据库事务操作。
  • 确认发送消息,RocketMQ将消息状态标记为可消费,这个时候消费者,才能真正的保证消费到这条数据。

如果确认消息发送失败了怎么办?

  • RocketMQ会定期扫描消息集群中的事务消息,如果发现了Prepared消息,它会向消息发送端(生产者)确认。
  • RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。
  • 这样就保证了消息发送与本地事务同时成功或同时失败。

如果消费失败怎么办?

  • 阿里提供的解决方法是:人工解决。

方案二:并不是所有的MQ都支持事务消息。

  • 也就是消息一旦发送到消息队列中,消费者立马就可以消费到,此时可以使用独立消息服务、或者本地事务表。

刚开始处于prepare状态,业务逻辑处理成功后,确认发送消息,这个时候 独立消息服务 才会真正的把消息发送给消息队列。

消费者消费成功后,ack时,除了对消息队列进行ack,对于独立消息服务也要进行ack,独立消息服务一般是把这条消息删除。

而定时扫描prepare状态的消息,向消息发送端(生产者)确认的工作也由独立消息服务来完成。

最大努力通知

适用于一些最终一致性时间敏感度低的业务,且被动方处理结果 不影响主动方的处理结果。

典型的使用场景:如银行通知、商户通知等。

最大努力通知型的实现方案,一般符合以下特点:

不可靠消息:

  • 业务活动主动方,在完成业务处理之后,向业务活动的被动方发送消息,直到通知N次后不再通知,允许消息丢失(不可靠消息)。

定期校对:

  • 业务活动的被动方,根据定时策略,向业务活动主动方查询(主动方提供查询接口),恢复丢失的业务消息。

举例:一个短信发送平台,背景是公司内部有多个业务都有发送短信的需求,如果每个业务独立实现短信发送功能,存在功能实现上的重复。

有一个短信平台项目,所有的业务方都接入这个短信平台,来实现发送短信的功能。

1、业务方将短信发送请求提交给短信平台

2、短信平台接收到要发送的短信,记录到数据库中,并标记其状态为已接收

3、短信平台调用外部短信发送供应商的接口,发送短信

4、更新短信发送状态为已发送

5、短信发送供应商异步通知短信平台短信发送结果,而通知可能失败,因此最多只会通知N次

6、短信平台接收到短信发送结果后,更新短信发送状态,可能是成功,也可能失败(如手机欠费)

7、如果最多只通知N次,如果都失败了的话,那么短信平台将不知道短信到底有没有成功发送

8、短信发送供应商需要提供一个查询接口,以方便短信平台驱动的去查询,进行定期校对

TCC事务

TCC将事务过程分为Try(尝试)、Confirm(确认)和Cancel(取消)三个阶段,每个阶段由业务代码控制,避免了长事务的问题,从而提高了性能。

Try阶段

  • 尝试执行业务并完成所有业务检查,预留业务资源。

Confirm和Cancel阶段:这两个操作是互斥的,只可以选择其中一个。

  • Confirm操作是确认提交,执行业务操作,不进行其他业务检查,只使用Try阶段预留的业务资源。
  • Cancel操作在业务执行错误需要回滚的情况下执行,释放预留的资源。

Try 阶段失败可以 Cancel,如果 Confirm 和 Cancel 阶段失败了呢?

TCC事务模型中会使用事务日志来记录Try、Confirm和Cancel阶段的操作。

如果在Confirm或Cancel阶段发生错误,系统会进行重试操作。

因此,这两个阶段需要支持幂等性,以确保多次执行的结果与一次执行的结果相同。

如果重试操作失败,就需要人工介入来进行恢复和处理。

TCC的缺点:

TCC对微服务的侵入性较强,需要对业务系统进行改造,每个分支的业务逻辑都需要实现try、confirm和cancel操作,并且confirm和cancel操作必须保证幂等性。

TCC的事务管理器需要记录事务日志,这也会带来一定的性能损耗。

与2PC/XA两阶段提交的区别:

2PC/XA关注数据库层面的强一致性,持有数据库锁。

而TCC关注业务层面的最终一致性,不涉及加锁,并且将相关的处理从数据库转移到业务中,实现跨数据库的事务。

空回滚问题:

在 try 阶段服务 发生了故障,try 阶段在不考虑重试的情况下,全局事务必须要走向结束状态,这样就需要在服务上执行一次 cancel 操作,这样就空跑了一次回滚操作。

解决办法:

  • 第一阶段 Try 方法里会插入一条记录(事务记录表),表示一阶段执行了。
  • Cancel 接口里读取该记录,如果该记录存在,则正常回滚;如果该记录不存在,则是空回滚。

防悬挂控制:

在调用TCC服务的一阶段Try操作时,可能会出现因网络拥堵而导致的超时,此时触发二阶段回滚,调用TCC服务的Cancel操作;

在此之后,拥堵在网络上的一阶段Try数据包被TCC服务收到,出现了二阶段Cancel请求比一阶段Try请求先执行的情况;

解决思路:

  • 如果二阶段执行完成,那一阶段就不能再继续执行。
  • 在执行一阶段事务时判断在该全局事务下,事务记录表中是否已经有二阶段事务记录,如果有则不执行Try。

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1519 4
|
29天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
5天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
507 19
|
2天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
179 1
|
8天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
21天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
9天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
457 5
|
7天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
315 2
|
23天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
25天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2608 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析