2024年前端最新从分布式事务解决到Seata使用,一梭子给你整明白了(1),2024年最新华为软件开发面试题

读者福利

========

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

由于篇幅过长,就不展示所有面试题了,想要完整面试题目的朋友(另有小编自己整理的2024大厂高频面试题及答案附赠)


整体上可以分为两个大的步骤:A服务向消息中间件发布消息 和 消息向B服务投递消息

步骤一: A 服务向消息中间件发布消息

  1. 在服务A处理任务A前,首先向消息中间件发送一条半信息

  2. 消息中间件收到后将该消息持久化,但不进行投递。持久化成功后,向A服务返回确认应答

  3. 服务A收到确认应答后,便可以开始处理任务A

  4. 任务A处理完成后,服务A便会向消息中间件发送Commit 或者 Rollback 请求,该请求发送完成后,服务A的工作任务就结束了,该事务的处理过程也就结束了

  5. 在消息中间件收到 Commit 后,便会向 B 服务投递消息,如果收到 Rollback 便会直接丢弃消息

如果消息中间件在最后的过程中,长时间没有收到服务A 发送的 Commit 或 Rollback 指令,这个时候就需要依靠 超时询问机制

超时询问机制

服务A除了实现正常的业务流程之外,还是需要提供一个可供消息中间件事务询问的接口。在消息中间件第一次收到消息后便会开始计时,如果超过规定的时间没有收到后续的指令,就会主动调用服务A提供的事务询问接口,询问当前服务的状态,通常来说该接口会返回三种结果,中间件需要根据这三种不同的结果做出不同的处理:

提交:直接将该消息投递给服务B 回滚:直接将该消息丢弃 处理中:继续等待,重新计时

步骤二: 消息中间件向B服务投递消息

消息中间件收到A服务的提交 Commit指令后便会将该消息投递给B服务,然后将自己的状态置为阻塞等待状态。B服务收到消息中间件发送的消息后便开始处理任务B,处理完成后便会向消息中间件发出回应。但是在消息中间件阻塞等待的时候同样会出现问题

  • 正常情况:消息中间件投递完消息后,进入阻塞等待状态,在收到确认应答后便认为事务处理完成,该流程结束

  • 等待超时情况:在等待确认应答超时之后就会重新进行投递,直到B服务器返回消费成功响应为止。而消息重试的次数和时间间隔都可以设置,如果最终还是不能成功进行投递,则需要人工干预。

可靠消息服务方案是实现了 最终一致性。对比本地消息表实现方案,不需要再建立消息表。不用依赖本地数据库事务,适用于高并发的场景。RocketMQ 就很好的支持了消息事务。

方法四:最大努力通知

==========

最大努力通知也成为定期校对,是对可靠消息服务的进一步优化。它引入了本地消息表来记录错误消息,然后加入失败消息的定期校对功能,来进一步保证消息会被下游服务消费。

从分布式事务解决到Seata使用,一梭子给你整明白了

同样的这个跟消息事务一样可以分为两步:

步骤一: 服务A向消息中间件发送消息

  1. 在处理业务的同一个事务中,向本地消息表写入一条记录

  2. 消息发送者不断取出本地消息表中的消息发送到消息中间件,如果发送失败则进行重试

步骤二: 消息中间件向服务B投递消息

  1. 消息中间件收到消息后便会将消息投递到下游服务B,服务B收到消息后便会执行自己的业务

  2. 当服务B业务处理成功后,便会向消息中间件返回反馈应答,消息中间件便可将该消息删除,该流程结束

  3. 如果消息中间件向服务B投递消息失败,便会尝试重试,如果重试失败,便会将该消息接入失败消息表中

  4. 消息中间件同样需要提供查询失败消息的接口,服务B 定期查询失败信息,并进行消费

最大努力通知的方案实现比较简单,适用于一些最终一致性要求比较低的业务。

Seata

=====

Seata概念

=======

既然分布式事务处理起来这么麻烦,那能不能让分布式事务处理起来像本地事务那么简单。当然这是我们的愿景。当然这个愿景是所有开发人员所希望的。而阿里巴巴团队就为这个愿景做出了行动,发起了开源项目 Seata(Simple Extensible Autonomous Transaction Architecture) 。这是一套分布式事务解决方案,意在解决开发人员遇到的分布式事务各方面的难题。

Seata 的设计目标是对业务无侵入,因此它是从业务无侵入的两阶段提交(全局事务)着手,在传统的两阶段上进行改进,他把一个分布式事务理解成一个包含了若干分支事务的全局事务。而全局事务的职责是协调它管理的分支事务达成一致性,要么一起成功提交,要么一起失败回滚。也就是一荣俱荣一损俱损~

从分布式事务解决到Seata使用,一梭子给你整明白了

Seata 组成

========

我们看下 Seata 中存在几种重要角色:

  • TC(Transaction Coordinator):事务协调者。管理全局的分支事务的状态,用于全局性事务的提交和回滚。

  • TM(Transaction Manager):事务管理者。用于开启、提交或回滚事务。

  • RM(Resource Manager):资源管理器。用于分支事务上的资源管理,向 TC 注册分支事务,上报分支事务的状态,接收 TC 的命令来提交或者回滚分支事务。

这是一种很巧妙的设计,我们来看图:

从分布式事务解决到Seata使用,一梭子给你整明白了

执行流程是这样的:

  1. 服务A中的 TM 向 TC 申请开启一个全局事务,TC 就会创建一个全局事务并返回一个唯一的 XID

  2. 服务A中的 RM 向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中

  3. 服务A开始执行分支事务

  4. 服务A开始远程调用B服务,此时 XID 会根据调用链传播

  5. 服务B中的 RM 也向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中

  6. 服务B开始执行分支事务

  7. 全局事务调用处理结束后,TM 会根据有误异常情况,向 TC 发起全局事务的提交或回滚

  8. TC 协调其管辖之下的所有分支事务,决定是提交还是回滚

Seata使用

=======

我们从上面了解到了 Seata 的组成和执行流程,我们接下来就来实际的使用下 Seata

示例演示

====

我们简单创建了一个微服务项目,其中有订单服务和库存服务。

从分布式事务解决到Seata使用,一梭子给你整明白了

我们这里采用了 nacos 作为注册中心,分别启动两个服务,我们在nacos控制台可以看到两个已经注册的服务:

从分布式事务解决到Seata使用,一梭子给你整明白了

号外:如果对nacos还不熟悉的小伙伴可以跳转查看 nacos讲解:微服务新秀之Nacos

我们接着创建了一个数据库,其中有两张表:c_order 和 c_product,其中商品表中有一条数据,而订单表中还未有数据,接下来我们将要对其进行操作!

从分布式事务解决到Seata使用,一梭子给你整明白了

我们现在模拟一个下单的过程:

  1. 请求进来,通过商品 pid 往数据库中查商品的信息

  2. 创建一条该商品的订单

  3. 对应扣减该商品的库存量

  4. 流程结束

从分布式事务解决到Seata使用,一梭子给你整明白了

我们接下来就进入代码演示一下:

从分布式事务解决到Seata使用,一梭子给你整明白了

注意:这里 ProductService 并非是库存服务里面的类,而是利用 Feign 远程调用库存服务的接口

代码三步走,正常请况下肯定是没有问题的:

从分布式事务解决到Seata使用,一梭子给你整明白了

订单生成,库存也对应减少,感觉自己代码可以上线进入正轨的时候,我们来模拟一下库存中的异常,库存商品数量归为 100,订单表清空:

从分布式事务解决到Seata使用,一梭子给你整明白了

我们继续发送下单请求,可以看到库存服务已经抛出了异常

从分布式事务解决到Seata使用,一梭子给你整明白了

正常来说这个时候,库存表数量不应该减少,订单表不应该插入订单数据,但是事实真的是这样的吗?我们看数据:

从分布式事务解决到Seata使用,一梭子给你整明白了

库存数量没减,但是订单却增加了。好了,到这里,你就已经见识到了分布式事务的灾难性危害。接下来主角登场!

从分布式事务解决到Seata使用,一梭子给你整明白了

Seata 安装

========

我们首先需要点击下载地址进行下载 Seata

由于我们是使用 nacos 作为服务中心和配置中心,因此我们下载解压后需要做一些修改操作

  • 进入 conf 目录编辑 registry.conf 和 file.conf 两个文件,编辑后内容如下:

从分布式事务解决到Seata使用,一梭子给你整明白了

从分布式事务解决到Seata使用,一梭子给你整明白了

  • 由于新版 Seata 中没有 nacos-conf.sh 和 config.txt 两个文件,因此我们需要独立下载:

nacos-config.sh 下载地址

config.txt 下载地址

我们需要将 config.txt 文件放到 seata 目录下,而非 conf 目录下,并且需要修改 config.txt 内容

从分布式事务解决到Seata使用,一梭子给你整明白了

从分布式事务解决到Seata使用,一梭子给你整明白了

config.txt就是seata各种详细的配置,执行 nacos-config.sh 即可将这些配置导入到nacos,这样就不需要将file.conf和registry.conf放到我们的项目中了,需要什么配置就直接从nacos中读取。

  • 执行导入

在 conf 目录下打开 git bash 窗口,执行以下命令:

sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t namespace-id(需要替换) -u nacos -w nacos

复制代码

操作结束后,我们便可以在 nacos 控制台中看到配置列表,日后配置有需要修改便可以直接从这边修改,而不用修改目录文件:

从分布式事务解决到Seata使用,一梭子给你整明白了

  • 数据库配置

在 1.4.1 最新版中依然没有 sql 文件,所以我们还是需要另外下载:sql 下载地址

在 seata 数据中执行这个文件,生成三张表:

从分布式事务解决到Seata使用,一梭子给你整明白了

在我们的业务数据库中执行 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;

复制代码

  • 添加 log 文件

如果我们没有log输出文件,启动 seata 可能会报错,因此我们需要在 seata 目录下创建 logs 文件夹,在 logs 文件下创建 seata_gc.log 文件

从分布式事务解决到Seata使用,一梭子给你整明白了

  • 启动

做好了以上准备,我们便可以启动 seata 了,直接在 bin 目录下 cmd 执行 bat 脚本即可,启动结束便可在 nacos 中看到 seata 服务:

从分布式事务解决到Seata使用,一梭子给你整明白了

Seata 集成

========

在 Seata 安装的步骤中我们便完成了 Seata 服务端 的启动安装,接下来就是在项目中集成 Seata 客户端

  • 第一步:我们需要在 pom.xml 文件中添加两个依赖:seata 依赖 和 nacos 配置依赖

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-config

com.alibaba.cloud

spring-cloud-starter-alibaba-seata

io.seata

seata-all

io.seata

seata-spring-boot-starter

io.seata

seata-all

1.4.1

io.seata

seata-spring-boot-starter

1.4.1

复制代码

注意: 这里需要排除

spring-cloud-starter-alibaba-seata 自带的 seata 依赖,然后引入我们自己需要的 seata 版本,如果版本不一致启动时可能会造成 no available server to connect 错误!

  • 第二步:我们需要把 restry.conf 文件复制到项目的 resource 目录下

从分布式事务解决到Seata使用,一梭子给你整明白了

  • 第三步:需要自己配置seata代理数据源

@Configuration

public class DataSourceProxyConfig {

@Bean

@ConfigurationProperties(prefix = “spring.datasource”)

public DruidDataSource druidDataSource() {

return new DruidDataSource();

}

@Primary

@Bean

public DataSourceProxy dataSource(DruidDataSource druidDataSource) {

return new DataSourceProxy(druidDataSource);

}

}

复制代码

配置完数据源我们得在启动类的 SpringBootApplication 上排除Druid数据源依赖,否则可能会出现循环依赖的错误:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

复制代码

  • 第四步:在 nacos 的配置文件控制台中加入我们服务的事务组项:

service.vgroupMapping + 服务名称 = default

group为: SEATA_GROUP

复制代码

从分布式事务解决到Seata使用,一梭子给你整明白了

  • 第五步:项目中配置修改

从分布式事务解决到Seata使用,一梭子给你整明白了

  • 第六步:开启全局事务

打开全栈工匠技能包-1小时轻松掌握SSR

两小时精通jq+bs插件开发

生产环境下如歌部署Node.js

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

网易内部VUE自定义插件库NPM集成

谁说前端不用懂安全,XSS跨站脚本的危害

webpack的loader到底是什么样的?两小时带你写一个自己loader

  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值