知识回顾
目前秒杀模型
传统事务回顾
事务定义
事务定义:
是数据库操作的最⼩⼯作单元,是作为单个逻辑⼯作单元执⾏的⼀系列操作;这些操作作为⼀个整体⼀起向系统提交,要么都执⾏、要么都不执⾏
传统事务知识点
四个特性(ACID)
-
原⼦性:事务是数据库的逻辑⼯作单位,事务中包含的各操作要么都做,要么都不做
-
⼀致性:事务执⾏的结果必须是使数据库从⼀个⼀致性状态变到另⼀个⼀致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于⼀致性状态。如果数据库系统运⾏中发⽣故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有⼀部分已写⼊物理数据库,这时数据库就处于⼀种不正确的状态,或者说是 不⼀致的状态。
-
隔离性:⼀个事务的执⾏不能其它事务⼲扰。即⼀个事务内部的操作及使⽤的数据对其它并发事务是隔离的,并发执⾏的各个事务之间不能互相⼲扰。
-
持久性:⼀个事务⼀旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执⾏结果有任何影响。
事务隔离级别
-
读未提交 (Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
-
读已提交(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别(不重复读)
-
可重复读(Repeated Read):在同⼀个事务内的查询都是事务开始时刻⼀致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读,但是innoDB解决了幻读
-
序列化:(Serializable):完全串⾏化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
事务的传播行为
Spring ⽀持 7 种事务传播⾏为:
org.springframework.transaction.annotation. Propagation
Propagation.REQUIRED 是常⽤的事务传播⾏为,如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加⼊到这个事务中。其它传播⾏为⼤家可另查阅。
传统事务引用场景举例
传统事务控制基础:必须得保证是同⼀个连接,通过jdbc操作数据源的话保证同⼀个connection 对象
传统事务问题
在分布式架构下,随着业务量的扩⼤,我们对业务进⾏拆分,数据库也会相应的进⾏分库分⽚,因为有着⽹络的不确定性,那么我们分布式环境下应该如何保证事务的ACID?
当单个数据库的性能产⽣瓶颈的时候,我们需要对数据库分库或者是分区,那么这个时候数据库就处于不同的服务器上了,因此基于单个数据库所控制的传统型事务已经不能在适应这种情况了,故我们需要使⽤分布式事务来管理这种情况
分布式事务
理论基础-CAP
概念
1998年,加州⼤学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。
-
⼀致性:Consistency
- 集群中各个结点的数据总是⼀致的,因此你可以向任意结点读写数据,并总是能得到相同的数据
-
可⽤性:Availability
- 可⽤性表示你总是能够访问集群(读/写),即使集群中的某个结点宕机了
-
分区容忍性:Partition toleranc
- 容忍集群持续运⾏,即使他们中存在分区(两个分区中的结点都是好的,只是分区之间不能通信)
**结论:分布式环境下,**CAP不能同时成⽴
模型解释
-
如上图所示,假如DB1和DB2都能够正常被访问,只是他们之间不能够互相通信,也就是他们之间不能够同步数据,这个时候我们容忍集群继续运⾏,那么我们说服务具有分区容忍性
-
那么现在在分区容忍性的前提之下:(DB1和DB2不能通⾏,服务继续运⾏)
现在向DB1中发送⼀条X=2的更新请求,Datebase1把X值更新为2,但是需要去同步到Database2,由于DB1和DB2不能够通⾏,所以同步会失败
A, 假如该条请求返回更新成功,那么会导致DB1和DB2数据不⼀致的情况出现,违背了⼀致性
B, 假如该条请求返回更新失败,那么我们认为DB1不可⽤了,违背了可⽤性
-
分布式系统在什么时候存在不满⾜分区容忍性的情况呢?
容忍集群持续运⾏,即使他们中存在分区 (两个分区中的结点都是好的,只是分区之间不能通信)
即P不存在,意思就是集群不能容忍分区的出现,也就是不能容忍两个节点之间不能通信的情况,⽽分布式环境下两个节点不能通信的情况是不存在的,因为节点之间的通信都是通过⽹络传输,⽹络是不“靠谱”的。
解决方案探索
刚性事务(强一致性)
定义:遵循ACID原则,强⼀致性。
代表:⼆阶段提交(2PC)
⼆阶段提交协议是协调所有分布式原⼦事务参与者,并决定提交或取消(回滚)的分布式算法。
引⼊了事务管理器
-
预备阶段
在请求阶段,协调者将通知事务参与者准备提交或取消事务,然后进⼊表决过程。 在表决过程中,参与者将告知协调者⾃⼰的决策:同意(事务参与者本地作业执⾏成功)或取消(本地作业执⾏故障)。
2.提交阶段
在该阶段,协调者将基于第⼀个阶段的投票结果进⾏决策:提交或取消。当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务。参与者在接收到协调者发来的消息后将执⾏响应的操作。
存在的问题:
-
同步阻塞问题:在执⾏的过程中,所有参与的节点都是事务型阻塞的,当参与者占有公共资源时,其他第三⽅节点访问公共资源不得不处于阻塞状态
-
不能解决数据不⼀致的问题
柔性事务(最终一致性)
定义
遵循BASE理论,最终⼀致性;与刚性事务不同,柔性事务允许⼀定时间内,不同节点的数据不⼀致,但要求最终⼀致。
Base理论
-
Basically Avaiable,基本可⽤
-
Soft state:软状态
-
Eventually consistent:最终⼀致性
既然⽆法做到强⼀致性,但每个应⽤都可以根据⾃身的业务特点,采⽤适当的⽅式来使系统达到最终⼀致性。
TCC事务
全称:Try-Confifirm-Cancel(可以理解为sql中的Lock、Commit、Rollback)
TCC是服务化的⼆阶段编程模型:
其 Try、Confifirm、Cancel 3 个⽅法均由业务编码实现:Try 操作作为⼀阶段,负责资源的检查和预留。Confifirm 操作作为⼆阶段提交操作,执⾏真正的业务。Cancel 是预留资源的取消。
事务流程
-
Try阶段:完成所有的业务检查,预留资源
-
Confifirm阶段:更改状态操作
-
Cancel阶段:当Try阶段存在服务执⾏失败时,则进⼊Cancel阶段
缺点:TCC的Try、Confirm、Cancel操作功能按照具体业务来实现,业务耦合度⾼,开发成本⾼
本地消息表
本地消息表这个⽅案最初是ebay提出的分布式事务完整⽅案
MQ事务消息
-
发送事务型消息,该消息暂时不可被消费
-
消息队列返回发送消息成功状态
-
本地事务收到消息发送成功状态,然后开始执⾏本地事务
- 假如本地事务执⾏成功,MQ消息发送⽅则会告诉MQServer表示这个消息可以被消费了,MQ会投递这个消息到MQ订阅⽅
- 假如本地事务执⾏失败,MQ消息发送⽅则会告诉MQServer需要丢弃之前发送的消息
-
假如MQServer⼀直没有收到MQ发送⽅的消息确认通知,会回查本地事务,查看本地事务是否执⾏成功,假如本地事务执⾏成功,那么会发送消息,假如本地事务执⾏失败,那么会丢弃事务,假如本地事务还在初始态,那么会过⼀会再来询问
-
消息在MQ订阅⽅的消息消费成功由MQ来保证
如何保证?(记下来,很重要)
-
MQ假如投递消息到MQ订阅⽅失败了,或者MQ订阅⽅消费消息失败了,那么MQ会把该消息丢⼊重试队列中,会重试发送该消息,默认16次,直到消息被消费成功为⽌
-
假如在16次之后该消息还没有被消费成功,那么MQ会再次把该消息丢⼊MQ死信队列中,对于死信队列的消息,我们需要⼿动去⼲预,让他消费成功(例如从后台管理系统⼿动(或者是定时任务)把死信队列中的消息拿出来,然后⼿动去执⾏操作,执⾏完成之后把消息从死信队列中删除掉)
其他解决方案
阿⾥GTS
成熟的⽅案,⼀站式解决,需要付费
参考链接:https://helpcdn.aliyun.com/product/48444.html
基于GTS的免费社区版本,SEATA
参考链接:https://github.com/seata/seata
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181101.html