java多线程    Java入门    vsftp    ftp    linux配置    centos    FRP教程    HBase    Html5缓存    webp    zabbix    分布式    neo4j图数据库    

分布式事务解决方案学习

结尾有总结:

第一部分:分布式事务的需求来源

传统本地事务的ACID原则

原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

一致性(Consistency)事务前后数据的完整性必须保持一致。比如A有500B有500,A转账给B 500 最终两人金额总和依然为1000才对

隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

Read Uncommitted (读取未提交内容)

Read Committed(读取提交内容)

Repeatable Read(可重读) MYSQL默认级别

Serializable 串行化

持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

https://java-er.com/blog/mysql-start-transaction/

https://blog.csdn.net/weixin_30553837/article/details/95049768

https://blog.csdn.net/ActionTech/article/details/119821863

原子性和持久性靠数据库的undo和redo

undo 数据库写入数据到磁盘之前,会先把数据缓存到内存,事务提交后才写入磁盘

简化过程

A事务开始

B记录a=1到undo.log buffer

C修改a=3

D将undo log写到磁盘

E将数据写到磁盘

F事务提交

如何保证持久性:

修改数据到磁盘前,只要事务提交了,就一定持久化了

如何保证原子性

每次用undo log来保证

redo

A事务开始

B记录a=1到undo.log buffer

C修改a=3

D 记录a=3 到redolog buffer

E 将undo log写到 redo log

F 将red log 写入磁盘

G事务提交---异步写入数据到磁盘

Redo 提升性能,把数据写磁盘换成了redo log写磁盘

redo log写磁盘速度比数据库快,因为redo log是顺序写,不用寻找地址

mysql写磁盘随机写,要去寻址,寻址效率低。数据库不能顺序写,索引文件

情况:redolog buffer满了,redolog写入了磁盘,未提交,机器崩溃,重启后,先执行redlog,再执行undolog还原

分布式1.跨数据库 2.跨服务 3.都跨

订单,库存,用户扣钱 三个服务,三个数据库

任何一个挂了,如何回滚

任何一个挂了,如何回滚

CAP理论

CAP: Consistency 一致性 Availblity 可用性 Partition tolerance 分区容错性

任何一个分布式系统无法同时满足三个

何时满足CP 一致性要求高,用zookeeper

何时满足AP 可用性要求高,用Eureka

Base理论

BASE 理论是对 CAP 中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性,让CAP三者同时基本实现

Basically Available 基本可用

Soft state 软状态

Eventually Consistent 最终一致(等一段时间一致所以基本可用 缩短异步服务器的同步时间比如10ms)

https://blog.csdn.net/qq_42651904/article/details/116886170

第二部分:分布式事务解决方案

方案1:分阶段提交:XA理论 eXtended Architecture

1994 年,X/Open 组织(即现在的 Open Group )定义了分布式事务处理的DTP 模型。该模型包括这样几个角色:

  • 应用程序( AP ):我们的微服务
  • 事务管理器( TM ):全局事务管理者
  • 资源管理器( RM ):一般是数据库
  • 通信资源管理器( CRM ):是TM和RM间的通信中间件

在该模型中,一个分布式事务(全局事务)可以被拆分成许多个本地事务,运行在不同的AP和RM上。每个本地事务的ACID很好实现,但是全局事务必须保证其中包含的每一个本地事务都能同时成功,若有一个本地事务失败,则所有其它事务都必须回滚。但问题是,本地事务处理过程中,并不知道其它事务的运行状态。因此,就需要通过CRM来通知各个本地事务,同步事务执行的状态。

XA就是 X/Open DTP中通信中间件与TM间联系的接口规范,定义了用于通知事务开始、提交、终止、回滚等接口,各个数据库厂商都必须实现这些接口。

二阶段提交

  1. 准备阶段:各自准备自己的事务
  2. 执行阶段:根据上一阶段的结果,进行提交或者回滚

协调者,参与者

协调者通知三个参与者,订单,库存,用户执行,返回结果给协调者

三个参与者都执行成功,才都提交,事务成功,如果任意一个失败了,大家都回滚

缺点:1.单点故障,协调者挂了 2.资源锁定,参与者执行完毕,不能释放资源,要等其他人,资源相互等待,再提交。如果任意一个挂了,另外两个一直等,死锁了

优点:强一致 Spring里有成熟框架,性能差,不推荐

方案 2.TCC

Try:资源检测和预留

Confirm:提交

Cancel:撤销

Try:库存10个买了2个,留着不要给别人

  1. try问三个服务预留成功通知大家
  2. confirm,如果不成功预留回滚

三阶段:独立事务,互不影响

  1. 直接自己操作,不等,各自为政
  2. 如果三个成功了,成功
  3. 如果任意一个失败了,不是回滚,反向操作。

优点:避开资源相互等待,效率高,缺点:1. 复杂性提升,本来一个业务变成了3个业务。2.都是try,confirm,cancel 开发成本加大,cancel开发了很多补偿机制。3.安全问题:补偿失败了怎么办,再补偿

TCC对开发人员要求比较高 TCC详细解释:https://zhuanlan.zhihu.com/p/462669898
这篇也很清楚简单 https://blog.csdn.net/vincent_wen0766/article/details/114089317

3 可靠消息服务

  • 事务发起者A执行本地事务
  • A通过 MQ把需要执行的事务发给B
  • B接受消息后,执行本地事务

类似饭馆的小票

从业务无法导致主业务的回滚,从业务可能反复重试,不知道什么时候成功

MQ必须保证可靠,所以叫可靠消息

本地消息表的方式来保证消息可靠,Rocket MQ的本地事务就是本地消息

服务模块:A--消息服务-- B

Rabbit MQ 靠消息确认的机制来确保消息一定成功,靠回调成功返回给业务A,可靠性不如Rocket MQ的本地数据库模式

RabbitMQ 镜像集群,可以保证高可靠

MQ队列,业务简单了,保证本地消息可靠性复杂了,但是消息自己解决了问题

消息服务更多资料
https://zhuanlan.zhihu.com/p/462665440

4. AT模式 Automatic Transaction

一阶段执行完毕,直接提交,不用try,直接减库存

二阶段失败,反向操作。反向操作由框架全自动实现

自动拦截SQL语句,记录where条件,字段条件,保存到一个镜像,如果失败,自动回滚。

兼备了TCC的优点(避免自己写回滚),XA的优点(避免资源锁定)

缺陷:比TCC性能差点

三个模块

TC 事务协调者。TM事务管理器 RM资源管理器

5.Seata

Seata集成了三种模式

总结:

1.分阶段提交XA

两个阶段1.各自准备事务 2.根据第一个阶段的结果决定提交或者回滚。任意一个阶段失败,集体回滚

2.TCC

1.直接自己操作,不等,各自为政
2.如果三个成功了,成功
3.如果任意一个失败了,不是回滚,反向操作。

3.可靠消息服务

事务发起者A执行本地事务
A通过 MQ把需要执行的事务发给B
B接受消息后,执行本地事务

加强版.AT模式 Automatic Transaction

TCC自动版本 反向操作由框架全自动实现

集成版.Seata Seata集成了三种模式

https://www.bilibili.com/video/BV1n7411R7WQ?p=1

扩充资料
https://baijiahao.baidu.com/s?id=1740686695130671946&wfr=spider&for=pc


This entry was posted in 高并发与大数据 and tagged , . Bookmark the permalink.
月小升QQ 2651044202, 技术交流QQ群 178491360
首发地址:月小升博客https://java-er.com/blog/disturb-task-study/
无特殊说明,文章均为月小升原创,欢迎转载,转载请注明本文地址,谢谢
您的评论是我写作的动力.

Leave a Reply