飞道的博客

分布式事务

423人阅读  评论(0)

事务

(1)事务特性

①原子性(Atomicity):事务的中的操作要么全部成功要么全部失败
②一致性(Consistency):事务必须使数据库从一个一致性状态到另一个一致性状态,例:A和B一起来有5000块,无论两者之间如何转账最后总量都必须为5000
③隔离性(Isolation):同时开启的两个事务之间互不干扰
④持久性(Durability):指一个事务一旦提交,那么对数据库的保存都是以永久的

(2)事务并发问题

①脏读:一个事务读取过程中,读取到了另一个事务未提交的数据
②不可重复读:一个事务内多次查询同一数据却返回了不同的值,这是因为在查询间隔,数据被另一个数据修改并提交了.
③虚读|幻读:例事务A删除了表中的全部数据的同时事务B在表中又插了一条数据,当操作事务A 的用户再查看时发现库里还有条数据,就像产生了幻觉一样
注: 幻读和不可重复读都是读取了另一条已经提交的事务,不同的是不可重复读查 询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)

(3)事务的隔离级别

①读未提交(read uncommited):最低级别,事务并发(①②③)都可能发生
②读已提交(read commited):可避免脏读的发生,事务并发(②③)可能发生
③可重复度(repeatable read):可避免脏读和不可重复读,事务并发(③)可能发生
④串行化(serialiable):事务排队一个接着一个进行,可避免事务并发问题

spring封装了事务管理代码

1.事务操作

(1) 事务操作对象:因为不同的平台操作事务的代码不相同,所以spring提供了一个接口
(2) PlatFormTransactionManager:接口
根据不同的环境使用不同的实现类:DataSourceTransactionManager,Hiber bateManager
注:在spring中事务的管理最重要的就是TransactionManager对象
(3) spring管理事务的属性介绍
①事务的隔离级别
②是否只读
③事务的传播行为

2.spring管理事务的方式

(1)编码式(了解)
(2)xml配置(aop)
①导包(4{core,beans,context,expression}+2(logging,log4j)
+2(aop+aspects)+2{weving+aopalliance}+spring-tx )
②导入约束

③配置详解


其他代码同模板初体验
aop:advisor大多用于事务管理。
aop:aspect大多用于日志、缓存。
(3)注解配置(aop)
①导包(同配置详解)
②导入约束(同配置详解)
③开启注解管理事务

④使用注解

3.事务传播特性

a方法头上标注了@Transactional注解,b方法头上页标注了@Transactional注解,且b方法中调用a方法这样就出现了事务的传播

Spring中通过Propagation来设置事务的传播属性的,在这个属性中提供了我们其中关于事务传播的特性:

  1. REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  2. SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  3. MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
  4. REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  5. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  6. NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  7. NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。

springboot中的事务

springboot事务的自动配置
TransactionAutoConfiguration

springboot事务的坑

在一个方法里面,编写两个方法,内部调用的时候,会导致内部方法的事务设置失效,原因是没有用到内部调用方法代理对象的缘故,
事务使用代理对象控制,对事务的设置都是对代理对象,而内部调用等于直接调用方法绕过了代理步骤。

解决:使用代理对象来调用事务方法
1.引入依赖,以来内部帮我们依赖了aspectj

2.开启aspectj动态代理功能,以后所有的代理都是aspectj创建的,即使没有接口也可以创建动态代理。
exposeProxy = true对外暴漏代理功能

@EnableAspectJAutoProxy(exposeProxy = true)

3.本类内调使用代理对象

Person person = (Person)AopContext.currentProxy();
person.b()

分布式事务

分布式系统经常出现的异常

机器宕机,网络异常,消息丢失,消息乱序数,据错误,不可靠的tcp,存储数据丢失

分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在微服务架构中,几乎可以说是无法避免。

CAP定理与BASE理论

CAP定理:指的是在一个分布式系统中


一致性和可用性是冲突的,一致性是指若三个db都要同时存储一个数据,此时一台服务器由于网络原因无法存储数据。
若我们想要保持所有db的可用性,就会导致在访问时访问到的数据与其他两台db不一致。
若想保证数据一致性,在负载均衡时就要避开未正确存储数据的服务器。

分布式系统中实现一致性的raft算法

原理动画展示 raft算法
大致流程 : 存储请求,各db自旋时间,先旋完为候选,候选db请求选举操作,其他未自旋结束db选举领导,得票超一半db被选为领导,其他db为随从,选举与保持心跳连接,领导写入日志,心跳连接通知随从写入日志,各随从写入成功通知领导,若大多数成功,领导db写入数据并通知随从写入,随从写数据入。若在上述途中网络问题发生分区错误,会重新选取领导,若网络回复会自动跟随现有领导,写入日志并写入数据

面临的问题

对于大型互联网应用的场景,主机众多部署分散,而且现在的集群规模越来越大,所有节点故障,网络故障是常态,而且要保证服务可用性达到99.99%,既保证P和A,舍弃C

BASE理论 (基本可用)

对CAP理论的延伸,思想是即使无法做到强一致性(CAP的一致性就是强一致性),但可以采用适度的弱一致性,即最终一致性

强一致性,弱一致性,最终一致性

多进程并发访问,更新后的数据在不同进程如何获取的不同策略,强一致性:要求更新后的数据立刻能被看到,弱一致性能够容忍后续的部分或者全部访问不到,最终一致性在经过一段时间后要求能够访问更新后的数据

分布式事务集中解决方案

2PC/CA模式(了解)



柔性事务

刚性事务遵循ACID原则,强一致性,柔性事务遵循BASE理论弱一致性,允许一定时间内,不同节点数据不一致,但要求最终一致。

TCC事务补偿性方案(3pc的手动版)


最大努力通知型方案

可靠消息 + 最终一致性解决方案(异步确保类型)

解决分布式事务

springcould alibaba seata(分布式事务中间件)

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
术语
TC - 事务协调者: 维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM - 事务管理器: 定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM - 资源管理器: 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

AT模式解决分布式事务(不适合高并发业务)

两阶段提交协议的演变
一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:
-提交异步化,非常快速地完成。
-回滚通过一阶段的回滚日志进行反向补偿。
缺点
内部添加了各种锁,在高并发环境下性能太差

模拟业务:订单服务创建订单会调用库存服务扣库存,若失败订单回滚,库存也需要回滚
解决流程图:

1.为每个微服务创建 UNDO_LOG(回滚日志) 表

-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2.安装并启动服务(安装事务协调器)
从 https://github.com/seata/seata/releases,下载服务器软件包,将其解压缩。

在config/registry.conf文件下配置相关信息,注册中心类型及地址,seata服务器配置及配置文件存放方式这里使用file型
在config/file.conf文件(可以搬到nacos中),使用file型存放的配置文件

每个微服务都需:
将registry.conf和file.conf文件复制到resource中
file.conf 的 service.vgroup_mapping 配置必须和spring.application.name一致

使用seata-server.bat启动中间件

3.服务引入依赖

4.注入 DataSourceProxy
因为 Seata 通过代理数据源实现分支事务,如果没有注入,事务无法成功回滚

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

    /**
     * 需要将 DataSourceProxy 设置为主数据源,否则事务无法回滚
     *
     * @param druidDataSource The DruidDataSource
     * @return The default datasource
     */
    @Primary
    @Bean("dataSource")
    public DataSource dataSource(DruidDataSource druidDataSource) {
        return new DataSourceProxy(druidDataSource);
    }
}

6.给分布式大事务的入口标注@GlobalTransactional
7.每个远程的小事物(分支事务)使用@Transactional

可靠消息+最终一致性解决分布式事务

模拟业务:订单服务创建订单会调用库存服务扣库存,若失败订单回滚,库存也需要回滚

详细参考 https://blog.csdn.net/qq_35419179/article/details/105735131

锁定库存时,库存工作单数据也应该记录对应库存被锁定的信息(锁定库存的商品id,订单id,锁定的数量,锁定状态

下单成功,锁定库存成功,其他业务调用失败导致订单回滚 : 将库存锁定工作单放入延时队列,
解锁库存:根据取出队列中库存工作单,根据工作单给指定的库存的某个商品增加库存数(回滚操作)

消息积压,重复,丢失等解决方案

1.消息丢失

2.消息重复

3.消息积压


转载:https://blog.csdn.net/qq_35419179/article/details/106152982
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场