加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

再问你一遍,你真的了解分布式事务吗?

发布时间:2020-02-22 18:25:08 所属栏目:MySql教程 来源:站长网
导读:副标题#e# 图片来自 Pexels 本地事务 事务 Transaction 由一组 SQL 组成,具有四个 ACID 特性: Atomicity:原子性,构成事务的一组SQL,要么全部生效,要么全不生效,不会出现部分生效的情况。 Consistency:一致性,数据库经过事务操作后从一种状态转变为
副标题[/!--empirenews.page--]

再问你一遍,你真的了解分布式事务吗?

图片来自 Pexels

本地事务

事务 Transaction 由一组 SQL 组成,具有四个 ACID 特性:

Atomicity:原子性,构成事务的一组SQL,要么全部生效,要么全不生效,不会出现部分生效的情况。

Consistency:一致性,数据库经过事务操作后从一种状态转变为另一个状态。可以说原子性是从行为上描述,而一致性是从结果上描述。

Isolation:隔离性,事务操作的数据对象相对于其他事务操作的数据对象相互隔离,互不影响。

Durability:持久性,事务提交后,其结果就是永久性的,即使发生宕机(非磁盘损坏)。

事务实现

对于 MySQL 数据库(InnoDB 存储引擎)而言,隔离性是通过不同粒度的锁机制来实现事务间的隔离。

原子性、一致性和持久性通过 redo log 重做日志和 undo log 回滚日志来保证的。

redo log:当数据库对数据做修改的时候,需要把数据页从磁盘读到 buffer pool 中,然后在 buffer pool 中进行修改。

那么这个时候 buffer pool 中的数据页就与磁盘上的数据页内容不一致,称 buffer pool 的数据页为 dirty page 脏数据。

如果这个时候发生非正常的 DB 服务重启,那么这些数据还没在内存,并没有同步到磁盘文件中(注意,同步到磁盘文件是个随机 IO),也就是会发生数据丢失。

如果这个时候,能够在有一个文件,当 buffer pool 中的 data page 变更结束后,把相应修改记录记录到这个文件(注意,记录日志是顺序 IO)。

那么当 DB 服务发生 crash 的情况,恢复 DB 的时候,也可以根据这个文件的记录内容,重新应用到磁盘文件,数据保持一致。

undo log:undo 日志用于存放数据被修改前的值,如果修改出现异常,可以使用 undo 日志来实现回滚操作,保证事务的一致性。另外 InnoDB MVCC 事务特性也是基于 undo 日志实现的。

undo 日志分为 insert undo log(insert 语句产生的日志,事务提交后直接删除)和 update undo log(delete 和 update 语句产生的日志,由于该 undo log 可能提供 MVVC 机制使用,所以不能再事务提交时删除)。

问题引入

CAP 理论

再问你一遍,你真的了解分布式事务吗?

CAP 原则又称 CAP 定理,指的是在一个分布式系统中的一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。

CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。但由于在分布式系统中,分区容错性必然存在,所以只能在一致性和可用性妥协。

传统的 DBMS,如 MySQL 其实 CA 组合,在主从架构下,读写分离的情况下,是牺牲一定的一致性的(主从延迟)。

Base 理论:

base available,基本可用,分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。

soft state,软状态,允许系统中存在中间状态,这个状态不影响系统可用性。

eventually consistent,最终一致性,系统的中间状态经过短暂的时间后到达一致状态。

如何解决

场景举例

考虑这样一种业务场景,系统 A 调用系统 B 的退款服务进行退款,系统 A 更改内部退款状态,接着调用系统 C 的短信服务通知用户。

在这样的一个场景下,由于网络不可靠的必然存在,存在 A、B、C 三个系统之间一致性的问题。

本地表

针对上述场景,设计两张表:退款记录表和短信发送记录表以及相应的补偿 Job。

具体实现过程:

新增退款记录表,状态为处理中。

调用系统 B 的退款服务进行退款。

更新退款记录状态为对应的状态(成功/失败)。

如果退款成功,则新增短信发送记录,记录状态为待发送。

调用系统 C 的短信服务,发送短信。

更新短信发送记录为已发送。

退款补偿 Job,查询退款记录表中处理中的记录,调用系统 B 的退款服务,退款成功处理:

新增短信发送记录,记录状态为待发送。

调用系统 C 的短信服务,发送短信。

更新短信发送记录为已发送。

短信通知补偿 Job,查询短信发送记录中待发送的记录,调用系统 C 的短信服务:

调用系统 C 的短信服务,发送短信。

更新短信发送记录为已发送。

注意:

系统 B 和系统 C 需要根据调用方传的 uuid 支持幂等。

系统 A、B、C 会出现短暂的不一致,但最终一致。

事务消息

可以将其视为两阶段提交消息实现,以确保分布式系统中的最终一致性。事务性消息可确保本地事务的执行和消息的发送可以原子方式执行。

但是由于事务消息异步的特性,调用方拿不到消费方的处理结果,适用于不关心对方的返回结果/对方负责保证处理成功。

再问你一遍,你真的了解分布式事务吗?

针对上述场景,增加两个事务消息的方式解决一致性问题,系统 A 通过发送事务消息的方式与系统 B 和系统 C 进行交互。

具体实现过程:

发送退款的事务消息。

新增退款记录,状态为:处理中。

Commit 退款事务消息。

提供 MQ 事务 callback:

退款 callback 查询:有退款记录且为处理中则 Commit;其他则 Rollback。

发送短信 callback 查询:有退款记录且成功则 Commit;其他则 Rollback。

退款同步 Job,查询退款记录表中处理中的记录,调用系统 B 的退款查询接口同步状态,其中退款成功处理:

发送短信的事务消息

更新退款记录为成功

Commit 短信事务消息

相关理论

二阶段提交

(编辑:东莞站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读