Seata执行原理分析-AT、XA、TCC、SAGA比较

  1. 分布式事务简介
    1.1 本地事务
    大多数场景下,我们的应用都只需要操作单一的数据库,这种情况下的事务称之为本地事务(Local Transaction)。本地事务的ACID特性是数据库直接提供支持。本地事务应用架构如下所示:
    在这里插入图片描述

在JDBC编程中,我们通过java.sql.Connection对象来开启、关闭或者提交事务。代码如下所示:

Connection conn = ... //获取数据库连接 
conn.setAutoCommit(false); //开启事务 
try{   //...执行增删改查sql    
conn.commit(); //提交事务 
}catch (Exception e) {conn.rollback();//事务回滚 
}finally{
conn.close();//关闭链接 
} 

1.2 分布式事务
在微服务架构中,完成某一个业务功能可能需要横跨多个服务,操作多个数据库。这就涉及到到了分布式事务,需要操作的资源位于多个资源服务器上,而应用需要保证对于多个资源服务器的数据操作,要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同资源服务器的数据一致性。

典型的分布式事务应用场景

  1. 跨库事务
    跨库事务指的是,一个应用某个功能需要操作多个库,不同的库中存储不同的业务数据。下图演示了一个服务同时操作2个库的情况:
    在这里插入图片描述

  2. 分库分表
    通常一个库数据量比较大或者预期未来的数据量比较大,都会进行分库分表。如下图,将数据库B拆分成了2个库:
    在这里插入图片描述

    对于分库分表的情况,一般开发人员都会使用一些数据库中间件来降低sql操作的复杂性。如,对于sql:insert into user(id,name) values (1,“张三”),(2,“李四”)。这条sql是操作单库的语法,单库情况下,可以保证事务的一致性。 但是由于现在进行了分库分表,开发人员希望将1号记录插入分库1,2号记录插入分库2。所以数据库中间件要将其改写为2条sql,分别插入两个不同的分库,此时要保证两个库要不都成功,要不都失败,因此基本上所有的数据库中间件都面临着分布式事务的问题。

  3. 微服务架构
    下图演示了一个3个服务之间彼此调用的微服务架构:
    在这里插入图片描述

    Service A完成某个功能需要直接操作数据库,同时需要调用Service B和Service C,而Service B又同时操作了2个数据库,Service C也操作了一个库。需要保证这些跨服务调用对多个数据库的操作要么都成功,要么都失败,实际上这可能是最典型的分布式事务场景。
    小结:上述讨论的分布式事务场景中,无一例外的都直接或者间接的操作了多个数据库。如何保证事务的ACID特性,对于分布式事务实现方案而言,是非常大的挑战。同时,分布式事务实现方案还必须要考虑性能的问题,如果为了严格保证ACID特性,导致性能严重下降,那么对于一些要求快速响应的业务,是无法接受的。
    1.3 两阶段提交协议(2PC)
    两阶段提交(Two Phase Commit),就是将提交(commit)过程划分为2个阶段(Phase):
    阶段1:
    TM通知各个RM准备提交它们的事务分支。如果RM判断自己进行的工作可以被提交,那就对工作内容进行持久化,再给TM肯定答复;要是发生了其他情况,那给TM的都是否定答复。
    以mysql数据库为例,在第一阶段,事务管理器向所有涉及到的数据库服务器发出prepare"准备提交"请求,数据库收到请求后执行数据修改和日志记录等处理,处理完成后只是把事务的状态改成"可以提交",然后把结果返回给事务管理器。
    阶段2
    TM根据阶段1各个RM prepare的结果,决定是提交还是回滚事务。如果所有的RM都prepare成功,那么TM通知所有的RM进行提交;如果有RM prepare失败的话,则TM通知所有RM回滚自己的事务分支。
    以mysql数据库为例,如果第一阶段中所有数据库都prepare成功,那么事务管理器向数据库服务器发出"确认提交"请求,数据库服务器把事务的"可以提交"状态改为"提交完成"状态,然后返回应答。如果在第一阶段内有任何一个数据库的操作发生了错误,或者事务管理器收不到某个数据库的回应,则认为事务失败,回撤所有数据库的事务。数据库服务器收不到第二阶段的确认提交请求,也会把"可以提交"的事务回撤。
    在这里插入图片描述

两阶段提交方案下全局事务的ACID特性,是依赖于RM的。一个全局事务内部包含了多个独立的事务分支,这一组事务分支要么都成功,要么都失败。各个事务分支的ACID特性共同构成了全局事务的ACID特性。也就是将单个事务分支支持的ACID特性提升一个层次到分布式事务的范畴。
2PC存在的问题
同步阻塞问题
2PC 中的参与者是阻塞的。在第一阶段收到请求后就会预先锁定资源,一直到 commit 后才会释放。
单点故障
由于协调者的重要性,一旦协调者TM发生故障,参与者RM会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。
数据不一致
若协调者第二阶段发送提交请求时崩溃,可能部分参与者收到commit请求提交了事务,而另一部分参与者未收到commit请求而放弃事务,从而造成数据不一致的问题。
2.Seata是什么
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)
官网:https://seata.io/zh-cn/index.html
源码: https://github.com/seata/seata
seata版本:v1.5.1
2.1 Seata的三大角色
在 Seata 的架构中,一共有三个角色:
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。
在 Seata 中,一个分布式事务的生命周期如下:
1.TM 请求 TC 开启一个全局事务。TC 会生成一个 XID 作为该全局事务的编号。XID会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。
2.RM 请求 TC 将本地事务注册为全局事务的分支事务,通过全局事务的 XID 进行关联。
3.TM 请求 TC 告诉 XID 对应的全局事务是进行提交还是回滚。
4.TC 驱动 RM 们将 XID 对应的自己的本地事务进行提交还是回滚。
在这里插入图片描述

2.2 Seata AT模式的设计思路
Seata AT模式的核心是对业务无侵入,是一种改进后的两阶段提交,其设计思路如下:
一阶段:
业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:
提交异步化,非常快速地完成。
回滚通过一阶段的回滚日志进行反向补偿。
一阶段
业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。核心在于对业务sql进行解析,转换成undolog,并同时入库,这是怎么做的呢?

二阶段
分布式事务操作成功,则TC通知RM异步删除undolog

分布式事务操作失败,TM向TC发送回滚请求,RM 收到协调器TC发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚。

  1. Seata XA模式
    1.1 整体机制
    在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的
    支持,以 XA 协议的机制来管理分支事务的一种 事务模式。AT和XA模式数据源代理机制对比
    XA 模式的使用
    从编程模型上,XA 模式与 AT 模式保持完全一致。只需要修改数据源代理,即可实现 XA
    模式与 AT 模式之间的切换。
    1 @Bean(“dataSource”)
    2 public DataSource dataSource(DruidDataSource druidDataSource) {
    3 // DataSourceProxy for AT mode4 // return new DataSourceProxy(druidDataSource);
    5
    6 // DataSourceProxyXA for XA mode
    7 return new DataSourceProxyXA(druidDataSource);
    8 }
    1.2 Spring Cloud Alibaba整合Seata XA实战
    对比Seata AT模式配置,只需修改两个地方:
    微服务数据库不需要undo_log表,undo_log表仅用于AT模式
    修改数据源代码模式为XA模式
    1 seata:
    2 # 数据源代理模式 默认AT
    3 data‐source‐proxy‐mode: XA
  2. 什么是TCC
    TCC 基于分布式事务中的二阶段提交协议实现,它的全称为 Try-Confirm-Cancel,即资源
    预留(
    Try)、确认操作(
    Confirm)、取消操作(
    Cancel),他们的具体含义如下:
  3. Try:对业务资源的检查并预留;
  4. Confirm:对业务处理进行提交,即 commit 操作,只要 Try 成功,那么该步骤
    一定成功;
  5. Cancel:对业务处理进行取消,即回滚操作,该步骤回对 Try 预留的资源进行释
    放。
    XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会
    持有资源的锁。TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。
    TCC 是一种侵入式的分布式事务解决方案,以上三个操作都需要业务系统自行实现,对业
    务系统有着非常大的入侵性,设计相对复杂,但优点是 TCC 完全不依赖数据库,能够实现
    跨数据库、跨应用资源管理,对这些不同数据访问通过侵入式的编码方式实现一个原子操
    作,更好地解决了在各种复杂业务场景下的分布式事务问题。
    以用户下单为例
    try-commit
    try 阶段首先进行预留资源,然后在 commit 阶段扣除资源。如下图:try-cancel
    try 阶段首先进行预留资源,预留资源时扣减库存失败导致全局事务回滚,在 cancel 阶段
    释放资源。如下图:
    2.1 Seata TCC 模式
    一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,
    分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
    一阶段 prepare 行为二阶段 commit 或 rollback 行为
    在Seata中,AT模式与TCC模式事实上都是两阶段提交的具体实现,他们的区别在于:
    AT 模式基于 支持本地 ACID 事务的关系型数据库:
    一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志
    记录。
    二阶段 commit 行为:马上成功结束,自动异步批量清理回滚日志。
    二阶段 rollback 行为:通过回滚日志,自动生成补偿操作,完成数据回滚。
    相应的,TCC 模式不依赖于底层数据资源的事务支持:
    一阶段 prepare 行为:调用自定义的 prepare 逻辑。
    二阶段 commit 行为:调用自定义的 commit 逻辑。
    二阶段 rollback 行为:调用自定义的 rollback 逻辑。
    简单点概括,SEATA的TCC模式就是手工的AT模式,它允许你自定义两阶段的处理逻辑而
    不依赖AT模式的undo_log。
    2.2 Seata TCC模式接口如何改造
    假设现有一个业务需要同时使用服务 A 和服务 B 完成一个事务操作,我们在服务 A 定义该
    服务的一个 TCC 接口:
    1 public interface TccActionOne {
    2 @TwoPhaseBusinessAction(name = “prepare”, commitMethod = “commit”, rollb
    ackMethod = “rollback”)
    3 public boolean prepare(BusinessActionContext actionContext, @BusinessAct
    ionContextParameter(paramName = “a”) String a);
    45 public boolean commit(BusinessActionContext actionContext);
    6
    7 public boolean rollback(BusinessActionContext actionContext);
    8 }
    同样,在服务 B 定义该服务的一个 TCC 接口:
    1 public interface TccActionTwo {
    2 @TwoPhaseBusinessAction(name = “prepare”, commitMethod = “commit”, rollb
    ackMethod = “rollback”)
    3 public void prepare(BusinessActionContext actionContext, @BusinessAction
    ContextParameter(paramName = “b”) String b);
    4
    5 public void commit(BusinessActionContext actionContext);
    6
    7 public void rollback(BusinessActionContext actionContext);
    8 }
    在业务所在系统中开启全局事务并执行服务 A 和服务 B 的 TCC 预留资源方法:
    1 @GlobalTransactional
    2 public String doTransactionCommit(){
    3 //服务A事务参与者
    4 tccActionOne.prepare(null,“one”);
    5 //服务B事务参与者
    6 tccActionTwo.prepare(null,“two”);
    7 }
    以上就是使用 Seata TCC 模式实现一个全局事务的例子,TCC 模式同样使
    用 @GlobalTransactional 注解开启全局事务,而服务 A 和服务 B 的 TCC 接口为事务参
    与者,Seata 会把一个 TCC 接口当成一个 Resource,也叫 TCC Resource。
    2.3 TCC如何控制异常
    在 TCC 模型执行的过程中,还可能会出现各种异常,其中最为常见的有空回滚、幂等、悬
    挂等。TCC 模式是分布式事务中非常重要的事务模式,但是幂等、悬挂和空回滚一直是
    TCC 模式需要考虑的问题,Seata 框架在 1.5.1 版本完美解决了这些问题。
    ResourceManager
    如何处理空回滚
    空回滚指的是在一个分布式事务中,在没有调用参与方的 Try 方法的情况下,TM 驱动二阶
    段回滚调用了参与方的 Cancel 方法。
    那么空回滚是如何产生的呢?如上图所示,全局事务开启后,参与者 A 分支注册完成之后会执行参与者一阶段 RPC 方
    法,如果此时参与者 A 所在的机器发生宕机,网络异常,都会造成 RPC 调用失败,即参与
    者 A 一阶段方法未成功执行,但是此时全局事务已经开启,Seata 必须要推进到终态,在
    全局事务回滚时会调用参与者 A 的 Cancel 方法,从而造成空回滚。
    要想防止空回滚,那么必须在 Cancel 方法中识别这是一个空回滚,Seata 是如何做的呢?
    Seata 的做法是新增一个 TCC 事务控制表,包含事务的 XID 和 BranchID 信息,在 Try 方
    法执行时插入一条记录,表示一阶段执行了,执行 Cancel 方法时读取这条记录,如果记录
    不存在,说明 Try 方法没有执行。
    如何处理幂等
    幂等问题指的是 TC 重复进行二阶段提交,因此 Confirm/Cancel 接口需要支持幂等处理,
    即不会产生资源重复提交或者重复释放。
    那么幂等问题是如何产生的呢?如上图所示,参与者 A 执行完二阶段之后,由于网络抖动或者宕机问题,会造成 TC 收不
    到参与者 A 执行二阶段的返回结果,TC 会重复发起调用,直到二阶段执行结果成功。
    Seata 是如何处理幂等问题的呢?
    同样的也是在 TCC 事务控制表中增加一个记录状态的字段 status,该字段有 3 个值,分别
    为:
  6. tried:1
  7. committed:2
  8. rollbacked:3
    二阶段 Confirm/Cancel 方法执行后,将状态改为 committed 或 rollbacked 状态。当重
    复调用二阶段 Confirm/Cancel 方法时,判断事务状态即可解决幂等问题。
    如何处理悬挂
    悬挂指的是二阶段 Cancel 方法比 一阶段 Try 方法优先执行,由于允许空回滚的原因,在
    执行完二阶段 Cancel 方法之后直接空回滚返回成功,此时全局事务已结束,但是由于 Try
    方法随后执行,这就会造成一阶段 Try 方法预留的资源永远无法提交和释放了。那么悬挂是如何产生的呢?
    如上图所示,在执行参与者 A 的一阶段 Try 方法时,出现网路拥堵,由于 Seata 全局事务
    有超时限制,执行 Try 方法超时后,TM 决议全局回滚,回滚完成后如果此时 RPC 请求才
    到达参与者 A,执行 Try 方法进行资源预留,从而造成悬挂。
    Seata 是怎么处理悬挂的呢?
    在 TCC 事务控制表记录状态的字段 status 中增加一个状态:
    suspended:4
    当执行二阶段 Cancel 方法时,如果发现 TCC 事务控制表有相关记录,说明二阶段 Cancel
    方法优先一阶段 Try 方法执行,因此插入一条 status=4 状态的记录,当一阶段 Try 方法后
    面执行时,判断 status=4 ,则说明有二阶段 Cancel 已执行,并返回 false 以阻止一阶段
    Try 方法执行成功。
    2.4 Spring Cloud Alibaba整合Seata TCC实战业务场景
    用户下单,整个业务逻辑由三个微服务构成:
    库存服务:对给定的商品扣除库存数量。
    订单服务:根据采购需求创建订单。
    帐户服务:从用户帐户中扣除余额。
  1. 环境准备
    父pom指定微服务版本
    Spring Cloud Alibaba
    Version
    Spring Cloud Version
    Spring Boot
    Version
    Seata
    Version
    2.2.8.RELEASE
    Spring Cloud Hoxton.SR12 2.3.12.RELEASE
    1.5.1
    启动Seata Server(TC)端,Seata Server使用nacos作为配置中心和注册中心启动nacos服务
  2. 微服务导入seata依赖
    spring-cloud-starter-alibaba-seata内部集成了seata,并实现了xid传递
    1 <!‐‐ seata‐‐>
    2
    3 com.alibaba.cloud
    4 spring‐cloud‐starter‐alibaba‐seata
    5
    3)微服务application.yml中添加seata配置
    1 seata:
    2 application‐id: ${spring.application.name}
    3 # seata 服务分组,要与服务端配置service.vgroup_mapping的后缀对应
    4 tx‐service‐group: default_tx_group
    5 registry:
    6 # 指定nacos作为注册中心
    7 type: nacos
    8 nacos:
    9 application: seata‐server
    10 server‐addr: 127.0.0.1:8848
    11 namespace:
    12 group: SEATA_GROUP
    13
    14 config:
    15 # 指定nacos作为配置中心
    16 type: nacos
    17 nacos:
    18 server‐addr: 127.0.0.1:8848
    19 namespace: 7e838c12‐8554‐4231‐82d5‐6d93573ddf32
    20 group: SEATA_GROUP
    21 data‐id: seataServer.properties
    注意:请确保client与server的注册中心和配置中心namespace和group一致
    4)定义TCC接口
    TCC相关注解如下:
    @LocalTCC 适用于SpringCloud+Feign模式下的TCC,@LocalTCC一定需要
    注解在接口上,此接口可以是寻常的业务接口,只要实现了TCC的两阶段提交对应方
    法便可@TwoPhaseBusinessAction 注解try方法,其中name为当前tcc方法的bean名
    称,写方法名便可(全局唯一),commitMethod指向提交方法,rollbackMethod
    指向事务回滚方法。指定好三个方法之后,seata会根据全局事务的成功或失败,去
    帮我们自动调用提交方法或者回滚方法。
    @BusinessActionContextParameter 注解可以将参数传递到二阶段

    commitMethod/rollbackMethod)的方法。
    BusinessActionContext 便是指TCC事务上下文
    1 /**
    2 * @author Fox
    3 *
    4 * 通过 @LocalTCC 这个注解,RM 初始化的时候会向 TC 注册一个分支事务。
    5 /
    6 @LocalTCC
    7 public interface OrderService {
    8
    9 /
    *
    10 * TCC的try方法:保存订单信息,状态为支付中
    11 *
    12 * 定义两阶段提交,在try阶段通过@TwoPhaseBusinessAction注解定义了分支事务的 r
    esourceId,commit和 cancel 方法
    13 * name = 该tcc的bean名称,全局唯一
    14 * commitMethod = commit 为二阶段确认方法
    15 * rollbackMethod = rollback 为二阶段取消方法
    16 * BusinessActionContextParameter注解 传递参数到二阶段中
    17 * useTCCFence seata1.5.1的新特性,用于解决TCC幂等,悬挂,空回滚问题,需增加
    日志表tcc_fence_log
    18 /
    19 @TwoPhaseBusinessAction(name = “prepareSaveOrder”, commitMethod = “comm
    it”, rollbackMethod = “rollback”, useTCCFence = true)
    20 Order prepareSaveOrder(OrderVo orderVo,
    @BusinessActionContextParameter(paramName = “orderId”) Long orderId);
    21
    22 /
    *
    23 *
    24 * TCC的confirm方法:订单状态改为支付成功
    25 *
    26 * 二阶段确认方法可以另命名,但要保证与commitMethod一致
    27 * context可以传递try方法的参数
    28 *
    29 * @param actionContext30 * @return
    31 /
    32 boolean commit(BusinessActionContext actionContext);
    33
    34 /
    *
    35 * TCC的cancel方法:订单状态改为支付失败
    36 * 二阶段取消方法可以另命名,但要保证与rollbackMethod一致
    37 *
    38 * @param actionContext
    39 * @return
    40 /
    41 boolean rollback(BusinessActionContext actionContext);
    42 }
    43
    44 /
    *
    45 * @author Fox
    46 *
    47 * 通过 @LocalTCC 这个注解,RM 初始化的时候会向 TC 注册一个分支事务。
    48 /
    49 @LocalTCC
    50 public interface StorageService {
    51
    52 /
    *
    53 * Try: 库存‐扣减数量,冻结库存+扣减数量
    54 *
    55 * 定义两阶段提交,在try阶段通过@TwoPhaseBusinessAction注解定义了分支事务的 r
    esourceId,commit和 cancel 方法
    56 * name = 该tcc的bean名称,全局唯一
    57 * commitMethod = commit 为二阶段确认方法
    58 * rollbackMethod = rollback 为二阶段取消方法
    59 * BusinessActionContextParameter注解 传递参数到二阶段中
    60 *
    61 * @param commodityCode 商品编号
    62 * @param count 扣减数量
    63 * @return
    64 /
    65 @TwoPhaseBusinessAction(name = “deduct”, commitMethod = “commit”, rollb
    ackMethod = “rollback”, useTCCFence = true)
    66 boolean deduct(@BusinessActionContextParameter(paramName = “commodityCo
    de”) String commodityCode,
    67 @BusinessActionContextParameter(paramName = “count”) int count);68
    69 /
    *
    70 *
    71 * Confirm: 冻结库存‐扣减数量
    72 * 二阶段确认方法可以另命名,但要保证与commitMethod一致
    73 * context可以传递try方法的参数
    74 *
    75 * @param actionContext
    76 * @return
    77 /
    78 boolean commit(BusinessActionContext actionContext);
    79
    80 /
    *
    81 * Cancel: 库存+扣减数量,冻结库存‐扣减数量
    82 * 二阶段取消方法可以另命名,但要保证与rollbackMethod一致
    83 *
    84 * @param actionContext
    85 * @return
    86 /
    87 boolean rollback(BusinessActionContext actionContext);
    88 }
    89
    90 /
    *
    91 * @author Fox
    92 *
    93 * 通过 @LocalTCC 这个注解,RM 初始化的时候会向 TC 注册一个分支事务。
    94 /
    95 @LocalTCC
    96 public interface AccountService {
    97
    98 /
    *
    99 * 用户账户扣款
    100 *
    101 * 定义两阶段提交,在try阶段通过@TwoPhaseBusinessAction注解定义了分支事务的
    resourceId,commit和 cancel 方法
    102 * name = 该tcc的bean名称,全局唯一
    103 * commitMethod = commit 为二阶段确认方法
    104 * rollbackMethod = rollback 为二阶段取消方法
    105 *
    106 * @param userId
    107 * @param money 从用户账户中扣除的金额108 * @return
    109 /
    110 @TwoPhaseBusinessAction(name = “debit”, commitMethod = “commit”, rollba
    ckMethod = “rollback”, useTCCFence = true)
    111 boolean debit(@BusinessActionContextParameter(paramName = “userId”) Str
    ing userId,
    112 @BusinessActionContextParameter(paramName = “money”) int money);
    113
    114 /
    *
    115 * 提交事务,二阶段确认方法可以另命名,但要保证与commitMethod一致
    116 * context可以传递try方法的参数
    117 *
    118 * @param actionContext
    119 * @return
    120 /
    121 boolean commit(BusinessActionContext actionContext);
    122
    123 /
    *
    124 * 回滚事务,二阶段取消方法可以另命名,但要保证与rollbackMethod一致
    125 *
    126 * @param actionContext
    127 * @return
    128 */
    129 boolean rollback(BusinessActionContext actionContext);
    130 }
    TCC 幂等、悬挂和空回滚问题如何解决?
    TCC 模式中存在的三大问题是幂等、悬挂和空回滚。在 Seata1.5.1 版本中,增加了一张事
    务控制表,表名是 tcc_fence_log 来解决这个问题。而在@TwoPhaseBusinessAction 注
    解中提到的属性 useTCCFence 就是来指定是否开启这个机制,这个属性值默认是 false。
    5)微服务增加tcc_fence_log日志表
    1 # tcc_fence_log 建表语句如下(
    MySQL 语法)
    2 CREATE TABLE IF NOT EXISTS tcc_fence_log
    3 (
    4 xid VARCHAR(128) NOT NULL COMMENT ‘global id’,
    5 branch_id BIGINT NOT NULL COMMENT ‘branch id’,
    6 action_name VARCHAR(64) NOT NULL COMMENT ‘action name’,
    7 status TINYINT NOT NULL COMMENT ‘status(tried:1;committed:2;rollbacke
    d:3;suspended:4)’,
    8 gmt_create DATETIME(3) NOT NULL COMMENT ‘create time’,9 gmt_modified DATETIME(3) NOT NULL COMMENT ‘update time’,
    10 PRIMARY KEY (xid, branch_id),
    11 KEY idx_gmt_modified (gmt_modified),
    12 KEY idx_status (status)
    13 ) ENGINE = InnoDB
    14 DEFAULT CHARSET = utf8mb4;
    6)TCC接口的业务实现
    参考课堂代码
    7) 在全局事务发起者中添加@GlobalTransactional注解
    核心代码
    1 @GlobalTransactional(name=“createOrder”,rollbackFor=Exception.class)
    2 public Order saveOrder(OrderVo orderVo) {
    3 log.info(“=用户下单=====”);
    4 log.info(“当前 XID: {}”, RootContext.getXID());
    5
    6 //获取全局唯一订单号 测试使用
    7 Long orderId = UUIDGenerator.generateUUID();
    8
    9 //阶段一: 创建订单
    10 Order order = orderService.prepareSaveOrder(orderVo,orderId);
    11
    12 //扣减库存
    13 storageFeignService.deduct(orderVo.getCommodityCode(),
    orderVo.getCount());
    14 //扣减余额
    15 accountFeignService.debit(orderVo.getUserId(), orderVo.getMoney());
    16
    17 return order;
    18 }
    8)测试分布式事务是否生效
    分布式事务成功,模拟正常下单、扣库存,扣余额
    分布式事务
  1. Seata快速开始
    Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。
    3.1 Seata Server(TC)环境搭建
    Server端存储模式(store.mode)支持三种:
    file:单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高
    db:高可用模式,全局事务会话信息通过db共享,相应性能差些
    redis:1.3及以上版本支持,性能较高,存在事务信息丢失风险,请提前配置适合当前场景的redis持久化配置
    资源目录:
    https://github.com/seata/seata/tree/v1.5.1/script
    client
    存放client端sql脚本,参数配置
    config-center
    各个配置中心参数导入脚本,config.txt(包含server和client)为通用参数文件
    server
    server端数据库脚本及各个容器配置
    db存储模式+Nacos(注册&配置中心)方式部署
    步骤一:下载安装包
    https://github.com/seata/seata/releases

步骤二:建表(db模式)
创建数据库seata,执行sql脚本,https://github.com/seata/seata/tree/v1.5.1/script/server/db

步骤三:配置Nacos注册中心
注册中心可以说是微服务架构中的”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到注册中心,当服务需要调用其它服务时,就到注册中心找到服务的地址,进行调用。比如Seata Client端(TM,RM),发现Seata Server(TC)集群的地址,彼此通信。
注意:Seata的注册中心是作用于Seata自身的,和Spring Cloud的注册中心无关

Seata支持哪些注册中心?
1.eureka
2.consul
3.nacos
4.etcd
5.zookeeper
6.sofa
7.redis
8.file (直连)
配置将Seata Server注册到Nacos,修改conf/application.yml文件
registry: # support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
cluster: default
username:
password:
注意:请确保client与server的注册处于同一个namespace和group,不然会找不到服务。

启动 Seata-Server 后,会发现Server端的服务出现在 Nacos 控制台中的注册中心列表中。
步骤四:配置Nacos配置中心
配置中心可以说是一个"大货仓",内部放置着各种配置文件,你可以通过自己所需进行获取配置加载到对应的客户端。比如Seata Client端(TM,RM),Seata Server(TC),会去读取全局事务开关,事务会话存储模式等信息。
注意:Seata的配置中心是作用于Seata自身的,和Spring Cloud的配置中心无关
Seata支持哪些配置中心?
1.nacos
2.consul
3.apollo
4.etcd
5.zookeeper
6.file (读本地文件, 包含conf、properties、yml配置文件的支持)
1)配置Nacos配置中心地址,修改conf/application.yml文件
seata: config: # support: nacos, consul, apollo, zk, etcd3 type: nacos nacos: server-addr: 127.0.0.1:8848 namespace: 7e838c12-8554-4231-82d5-6d93573ddf32 group: SEATA_GROUP data-id: seataServer.properties username: password:

2)上传配置至Nacos配置中心
https://github.com/seata/seata/tree/v1.5.1/script/config-center
a) 获取/seata/script/config-center/config.txt,修改为db存储模式,并修改mysql连接配置
store.mode=db store.lock.mode=db store.session.mode=db store.db.driverClassName=com.mysql.jdbc.Driver store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true store.db.user=root store.db.password=root
在store.mode=db,由于seata是通过jdbc的executeBatch来批量插入全局锁的,根据MySQL官网的说明,连接参数中的rewriteBatchedStatements为true时,在执行executeBatch,并且操作类型为insert时,jdbc驱动会把对应的SQL优化成insert into () values (), ()的形式来提升批量插入的性能。 根据实际的测试,该参数设置为true后,对应的批量插入性能为原来的10倍多,因此在数据源为MySQL时,建议把该参数设置为true。

b) 配置事务分组, 要与client配置的事务分组一致
事务分组:seata的资源逻辑,可以按微服务的需要,在应用程序(客户端)对自行定义事务分组,每组取一个名字。
集群:seata-server服务端一个或多个节点组成的集群cluster。 应用程序(客户端)使用时需要指定事务逻辑分组与Seata服务端集群的映射关系。

事务分组如何找到后端Seata集群(TC)?
1.首先应用程序(客户端)中配置了事务分组(GlobalTransactionScanner 构造方法的txServiceGroup参数)。若应用程序是SpringBoot则通过seata.tx-service-group 配置。
2.应用程序(客户端)会通过用户配置的配置中心去寻找service.vgroupMapping .[事务分组配置项],取得配置项的值就是TC集群的名称。若应用程序是SpringBoot则通过seata.service.vgroup-mapping.事务分组名=集群名称 配置
3.拿到集群名称程序通过一定的前后缀+集群名称去构造服务名,各配置中心的服务名实现不同(前提是Seata-Server已经完成服务注册,且Seata-Server向注册中心报告cluster名与应用程序(客户端)配置的集群名称一致)
4.拿到服务名去相应的注册中心去拉取相应服务名的服务列表,获得后端真实的TC服务列表(即Seata-Server集群节点列表)
c) 在nacos配置中心中新建配置,dataId为seataServer.properties,配置内容为上面修改后的config.txt中的配置信息
从v1.4.2版本开始,seata已支持从一个Nacos dataId中获取所有配置信息,你只需要额外添加一个dataId配置项。

添加后查看:

步骤五:启动Seata Server
启动命令:
bin/seata-server.sh

启动成功,查看控制台,账号密码都是seata。http://localhost:7091/#/login

在Nacos注册中心中可以查看到seata-server注册成功

支持的启动参数
参数 全写 作用 备注
-h --host 指定在注册中心注册的 IP 不指定时获取当前的 IP,外部访问部署在云环境和容器中的 server 建议指定
-p --port 指定 server 启动的端口 默认为 8091
-m --storeMode 事务日志存储方式 支持file,db,redis,默认为 file 注:redis需seata-server 1.3版本及以上
-n --serverNode 用于指定seata-server节点ID 如 1,2,3…, 默认为 1
-e --seataEnv 指定 seata-server 运行环境 如 dev, test 等, 服务启动时会使用 registry-dev.conf 这样的配置
比如:
bin/seata-server.sh -p 8091 -h 127.0.0.1 -m db
3.2 Seata Client快速开始
Spring Cloud Alibaba整合Seata AT模式实战
业务场景
用户下单,整个业务逻辑由三个微服务构成:
库存服务:对给定的商品扣除库存数量。
订单服务:根据采购需求创建订单。
帐户服务:从用户帐户中扣除余额。

  1. 环境准备
    启动Seata Server(TC)端,Seata Server使用nacos作为配置中心和注册中心
    启动nacos服务
  2. 微服务导入seata依赖
    spring-cloud-starter-alibaba-seata内部集成了seata,并实现了xid传递
com.alibaba.cloud spring-cloud-starter-alibaba-seata

3)微服务对应数据库中添加undo_log表(仅AT模式)
https://github.com/seata/seata/blob/v1.5.1/script/client/at/db/mysql.sql
– for AT mode you must to init this sql for you business database. the seata server not need it. CREATE TABLE IF NOT EXISTS undo_log ( branch_id BIGINT NOT NULL COMMENT ‘branch transaction id’, xid VARCHAR(128) NOT NULL COMMENT ‘global transaction id’, context VARCHAR(128) NOT NULL COMMENT ‘undo_log context,such as serialization’, rollback_info LONGBLOB NOT NULL COMMENT ‘rollback info’, log_status INT(11) NOT NULL COMMENT ‘0:normal status,1:defense status’, log_created DATETIME(6) NOT NULL COMMENT ‘create datetime’, log_modified DATETIME(6) NOT NULL COMMENT ‘modify datetime’, UNIQUE KEY ux_undo_log (xid, branch_id) ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT =‘AT transaction mode undo table’;
4) 微服务application.yml中添加seata配置
seata: application-id: ${spring.application.name} # seata 服务分组,要与服务端配置service.vgroup_mapping的后缀对应 tx-service-group: default_tx_group registry: # 指定nacos作为注册中心 type: nacos nacos: application: seata-server server-addr: 127.0.0.1:8848 namespace: group: SEATA_GROUP config: # 指定nacos作为配置中心 type: nacos nacos: server-addr: 127.0.0.1:8848 namespace: 7e838c12-8554-4231-82d5-6d93573ddf32 group: SEATA_GROUP data-id: seataServer.properties
注意:请确保client与server的注册中心和配置中心namespace和group一致
5) 在全局事务发起者中添加@GlobalTransactional注解
核心代码
@Override @GlobalTransactional(name=“createOrder”,rollbackFor=Exception.class) public Order saveOrder(OrderVo orderVo){ log.info(“=用户下单=====”); log.info(“当前 XID: {}”, RootContext.getXID()); // 保存订单 Order order = new Order(); order.setUserId(orderVo.getUserId()); order.setCommodityCode(orderVo.getCommodityCode()); order.setCount(orderVo.getCount()); order.setMoney(orderVo.getMoney()); order.setStatus(OrderStatus.INIT.getValue()); Integer saveOrderRecord = orderMapper.insert(order); log.info(“保存订单{}”, saveOrderRecord > 0 ? “成功” : “失败”); //扣减库存 storageFeignService.deduct(orderVo.getCommodityCode(),orderVo.getCount()); //扣减余额 accountFeignService.debit(orderVo.getUserId(),orderVo.getMoney()); //更新订单 Integer updateOrderRecord = orderMapper.updateOrderStatus(order.getId(),OrderStatus.SUCCESS.getValue()); log.info(“更新订单id:{} {}”, order.getId(), updateOrderRecord > 0 ? “成功” : “失败”); return order; }
6)测试分布式事务是否生效
分布式事务成功,模拟正常下单、扣库存,扣余额
分布式事务失败,模拟下单扣库存成功、扣余额失败,事务是否回滚

  1. Seata XA模式
    1.1 整体机制
    在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。

AT和XA模式数据源代理机制对比

XA 模式的使用
从编程模型上,XA 模式与 AT 模式保持完全一致。只需要修改数据源代理,即可实现 XA 模式与 AT 模式之间的切换。
@Bean(“dataSource”) public DataSource dataSource(DruidDataSource druidDataSource) { // DataSourceProxy for AT mode // return new DataSourceProxy(druidDataSource); // DataSourceProxyXA for XA mode return new DataSourceProxyXA(druidDataSource); }
1.2 Spring Cloud Alibaba整合Seata XA实战
对比Seata AT模式配置,只需修改两个地方:
微服务数据库不需要undo_log表,undo_log表仅用于AT模式
修改数据源代码模式为XA模式
seata: # 数据源代理模式 默认AT data-source-proxy-mode: XA
2. 什么是TCC
TCC 基于分布式事务中的二阶段提交协议实现,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel),他们的具体含义如下:
1.Try:对业务资源的检查并预留;
2.Confirm:对业务处理进行提交,即 commit 操作,只要 Try 成功,那么该步骤一定成功;
3.Cancel:对业务处理进行取消,即回滚操作,该步骤回对 Try 预留的资源进行释放。

XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。
TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。
TCC 是一种侵入式的分布式事务解决方案,以上三个操作都需要业务系统自行实现,对业务系统有着非常大的入侵性,设计相对复杂,但优点是 TCC 完全不依赖数据库,能够实现跨数据库、跨应用资源管理,对这些不同数据访问通过侵入式的编码方式实现一个原子操作,更好地解决了在各种复杂业务场景下的分布式事务问题。
以用户下单为例
try-commit
try 阶段首先进行预留资源,然后在 commit 阶段扣除资源。如下图:

try-cancel
try 阶段首先进行预留资源,预留资源时扣减库存失败导致全局事务回滚,在 cancel 阶段释放资源。如下图:

2.1 Seata TCC 模式
一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
一阶段 prepare 行为
二阶段 commit 或 rollback 行为

在Seata中,AT模式与TCC模式事实上都是两阶段提交的具体实现,他们的区别在于:
AT 模式基于 支持本地 ACID 事务的关系型数据库:
一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
二阶段 commit 行为:马上成功结束,自动异步批量清理回滚日志。
二阶段 rollback 行为:通过回滚日志,自动生成补偿操作,完成数据回滚。
相应的,TCC 模式不依赖于底层数据资源的事务支持:
一阶段 prepare 行为:调用自定义的 prepare 逻辑。
二阶段 commit 行为:调用自定义的 commit 逻辑。
二阶段 rollback 行为:调用自定义的 rollback 逻辑。
简单点概括,SEATA的TCC模式就是手工的AT模式,它允许你自定义两阶段的处理逻辑而不依赖AT模式的undo_log。
2.2 Seata TCC模式接口如何改造
假设现有一个业务需要同时使用服务 A 和服务 B 完成一个事务操作,我们在服务 A 定义该服务的一个 TCC 接口:
public interface TccActionOne { @TwoPhaseBusinessAction(name = “prepare”, commitMethod = “commit”, rollbackMethod = “rollback”) public boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = “a”) String a); public boolean commit(BusinessActionContext actionContext); public boolean rollback(BusinessActionContext actionContext); }
同样,在服务 B 定义该服务的一个 TCC 接口:
public interface TccActionTwo { @TwoPhaseBusinessAction(name = “prepare”, commitMethod = “commit”, rollbackMethod = “rollback”) public void prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = “b”) String b); public void commit(BusinessActionContext actionContext); public void rollback(BusinessActionContext actionContext); }
在业务所在系统中开启全局事务并执行服务 A 和服务 B 的 TCC 预留资源方法:
@GlobalTransactional public String doTransactionCommit(){ //服务A事务参与者 tccActionOne.prepare(null,“one”); //服务B事务参与者 tccActionTwo.prepare(null,“two”); }
以上就是使用 Seata TCC 模式实现一个全局事务的例子,TCC 模式同样使用 @GlobalTransactional 注解开启全局事务,而服务 A 和服务 B 的 TCC 接口为事务参与者,Seata 会把一个 TCC 接口当成一个 Resource,也叫 TCC Resource。
2.3 TCC如何控制异常
在 TCC 模型执行的过程中,还可能会出现各种异常,其中最为常见的有空回滚、幂等、悬挂等。TCC 模式是分布式事务中非常重要的事务模式,但是幂等、悬挂和空回滚一直是 TCC 模式需要考虑的问题,Seata 框架在 1.5.1 版本完美解决了这些问题。
如何处理空回滚
空回滚指的是在一个分布式事务中,在没有调用参与方的 Try 方法的情况下,TM 驱动二阶段回滚调用了参与方的 Cancel 方法。
那么空回滚是如何产生的呢?

如上图所示,全局事务开启后,参与者 A 分支注册完成之后会执行参与者一阶段 RPC 方法,如果此时参与者 A 所在的机器发生宕机,网络异常,都会造成 RPC 调用失败,即参与者 A 一阶段方法未成功执行,但是此时全局事务已经开启,Seata 必须要推进到终态,在全局事务回滚时会调用参与者 A 的 Cancel 方法,从而造成空回滚。
要想防止空回滚,那么必须在 Cancel 方法中识别这是一个空回滚,Seata 是如何做的呢?
Seata 的做法是新增一个 TCC 事务控制表,包含事务的 XID 和 BranchID 信息,在 Try 方法执行时插入一条记录,表示一阶段执行了,执行 Cancel 方法时读取这条记录,如果记录不存在,说明 Try 方法没有执行。
如何处理幂等
幂等问题指的是 TC 重复进行二阶段提交,因此 Confirm/Cancel 接口需要支持幂等处理,即不会产生资源重复提交或者重复释放。
那么幂等问题是如何产生的呢?

如上图所示,参与者 A 执行完二阶段之后,由于网络抖动或者宕机问题,会造成 TC 收不到参与者 A 执行二阶段的返回结果,TC 会重复发起调用,直到二阶段执行结果成功。
Seata 是如何处理幂等问题的呢?
同样的也是在 TCC 事务控制表中增加一个记录状态的字段 status,该字段有 3 个值,分别为:
1.tried:1
2.committed:2
3.rollbacked:3
二阶段 Confirm/Cancel 方法执行后,将状态改为 committed 或 rollbacked 状态。当重复调用二阶段 Confirm/Cancel 方法时,判断事务状态即可解决幂等问题。
如何处理悬挂
悬挂指的是二阶段 Cancel 方法比 一阶段 Try 方法优先执行,由于允许空回滚的原因,在执行完二阶段 Cancel 方法之后直接空回滚返回成功,此时全局事务已结束,但是由于 Try 方法随后执行,这就会造成一阶段 Try 方法预留的资源永远无法提交和释放了。
那么悬挂是如何产生的呢?

如上图所示,在执行参与者 A 的一阶段 Try 方法时,出现网路拥堵,由于 Seata 全局事务有超时限制,执行 Try 方法超时后,TM 决议全局回滚,回滚完成后如果此时 RPC 请求才到达参与者 A,执行 Try 方法进行资源预留,从而造成悬挂。
Seata 是怎么处理悬挂的呢?
在 TCC 事务控制表记录状态的字段 status 中增加一个状态:
suspended:4
当执行二阶段 Cancel 方法时,如果发现 TCC 事务控制表有相关记录,说明二阶段 Cancel 方法优先一阶段 Try 方法执行,因此插入一条 status=4 状态的记录,当一阶段 Try 方法后面执行时,判断 status=4 ,则说明有二阶段 Cancel 已执行,并返回 false 以阻止一阶段 Try 方法执行成功。

  1. ET 分布式事务解决方案之可靠消息最终一致性

1.什么是可靠消息最终一致性事务 可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能 够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致。 此方案是利用消息中间件完成,如下图: 事务发起方(消息生产方)将消息发给消息中间件,事务参与方从消息中间件接收消息,事务发起方和消息中间件 之间,事务参与方(消息消费方)和消息中间件之间都是通过网络通信,由于网络通信的不确定性会导致分布式事 务问题。

二、RocketMQ事务消息方案

1、RocketMQ 是一个来自阿里巴巴的分布式消息中间件,于 2012 年开源,并在 2017 年正式成为 Apache 顶级项 目。据了解,包括阿里云上的消息产品以及收购的子公司在内,阿里集团的消息产品全线都运行在 RocketMQ 之 上,并且最近几年的双十一大促中,RocketMQ 都有抢眼表现。
Apache RocketMQ 4.3之后的版本正式支持事务消 息,为分布式事务实现提供了便利性支持。
RocketMQ 事务消息设计则主要是为了解决 Producer 端的消息发送与本地事务执行的原子性问题,RocketMQ 的 设计中 broker 与 producer 端的双向通信能力,使得 broker 天生可以作为一个事务协调者存在;
而 RocketMQ 本身提供的存储机制为事务消息提供了持久化能力;
RocketMQ 的高可用机制以及可靠消息设计则为事务消息在系 统发生异常时依然能够保证达成事务的最终一致性。
在RocketMQ 4.3后实现了完整的事务消息,实际上其实是对本地消息表的一个封装,将本地消息表移动到了MQ 内部,解决 Producer 端的消息发送与本地事务执行的原子性问题。

2、执行流程如下:
为方便理解我们还以注册送积分的例子来描述 整个流程。
Producer 即MQ发送方,本例中是用户服务,负责新增用户。
MQ订阅方即消息消费方,本例中是积分服务,负责 新增积分。
2.1、Producer 发送事务消息 Producer (MQ发送方)发送事务消息至MQ Server,MQ Server将消息状态标记为Prepared(预备状态),注 意此时这条消息消费者(MQ订阅方)是无法消费到的。 本例中,Producer 发送 ”增加积分消息“ 到MQ Server。
2.2、MQ Server回应消息发送成功 MQ Server接收到Producer 发送给的消息则回应发送成功表示MQ已接收到消息。
2.3、Producer 执行本地事务 Producer 端执行业务代码逻辑,通过本地数据库事务控制。 本例中,Producer 执行添加用户操作。
2.4、消息投递 若Producer 本地事务执行成功则自动向MQServer发送commit消息,MQ Server接收到commit消息后将”增加积 分消息“ 状态标记为可消费,此时MQ订阅方(积分服务)即正常消费消息;
若Producer 本地事务执行失败则自动向MQServer发送rollback消息,MQ Server接收到rollback消息后 将删 除”增加积分消息“ 。 MQ订阅方(积分服务)消费消息,消费成功则向MQ回应ack,否则将重复接收消息。这里ack默认自动回应,即 程序执行正常则自动回应ack。
2.5、事务回查 如果执行Producer端本地事务过程中,执行端挂掉,或者超时,MQ Server将会不停的询问同组的其他 Producer 来获取事务执行状态,这个过程叫事务回查。MQ Server会根据事务回查结果来决定是否投递消息。 以上主干流程已由RocketMQ实现,对用户侧来说,用户需要分别实现本地事务执行以及本地事务回查方法,因此 只需关注本地事务的执行状态即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/411721.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

priority_queue模拟

一、什么是priority_queue? priority_queue是C标准库中的一个容器适配器&#xff0c;用于实现优先队列&#xff08;priority queue&#xff09;的数据结构。优先队列是一种特殊的队列&#xff0c;其中的元素按照一定的优先级进行排序&#xff0c;每次取出的元素都是优先级最高…

从零开始掌握Vue实例

从零开始掌握Vue实例&#xff1a;深入理解数据绑定与生命周期的核心秘诀 引言 简要介绍主题&#xff1a; 在学习Vue.js的过程中&#xff0c;Vue实例是最基础也是最关键的部分。Vue实例是Vue应用的核心&#xff0c;它是数据、DOM元素和Vue组件之间的桥梁。掌握Vue实例的使用对于…

文件上传面板中限制需要的文件格式,并且隐藏“所有文件”选项

直接说需求&#xff1a;需要实现在文件上传面板中限制需要的文件格式&#xff0c;并且不想展示“所有文件”这个选项&#xff0c;应该怎么做嘞&#xff1f;效果如下图&#xff1a; 这里用到了 window.showOpenFilePicker 方法实现&#xff0c;首先定义接受的格式及限制&#xf…

格行“信号增强技术”引领行业创新,格行随身WiFi带你感受不一样的速度与激情,行业第一的随身WiFi并非浪得虚名!

近年来&#xff0c;随着市场保有量的不断提升与相关技术的不断扩展&#xff0c;我国随身WiFi市场已经到了发展质量更高的“2.0”阶段&#xff0c;消费者对随身WiFi的需求变得多元且“高级”。与之对应的供给端&#xff0c;品牌之间的竞争也从未停止&#xff0c;有的品牌选择卷价…

如何使用ssm实现实验室仪器设备管理系统

TOC ssm354实验室仪器设备管理系统jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化…

快来尝尝,食家巷荞面甜甜圈超赞

当荞面与甜甜圈相遇&#xff0c;便诞生了食家巷荞面甜甜圈&#xff0c;一种独具特色的美食体验。 食家巷荞面甜甜圈&#xff0c;外形圆润可爱&#xff0c;色泽金黄诱人。那精致的环状造型&#xff0c;仿佛是一个小小的魔法圈&#xff0c;散发着迷人的魅力。 与传统甜甜圈…

计算机网络面试真题总结(七)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 什么是对称加密、非对称加密&#xff1f; 对称加密是一种常用的加…

探索AI智能问答:改变未来交流的新动力

人工智能(AI)是当今科技领域中最具潜力和影响力的技术之一&#xff0c;AI智能问答系统更是这一领域中的一颗璀璨明珠。随着大数据和机器学习的发展&#xff0c;AI智能问答系统已经不仅仅是科幻小说中的幻想&#xff0c;而是正逐步融入我们的日常生活&#xff0c;从客户服务到教…

生成式AI扩散模型-Diffusion Model【李宏毅2023】概念讲解、原理剖析笔记

目录 一、Diffusion的基本概念和运作方法 1.Diffusion Model是如何运作的&#xff1f; 2.Denoise模块内部正在做的事情 如何训练Noise predictor&#xff1f; 1&#xff09;Forward Process (Diffusion Process) 2&#xff09;noise predictor 3.Text-to-Image 4.两个A…

入门Java第一步—>IDEA的下载与安装与JDK的环境配置(day01)

1.JDK的下载与安装 jdk的安装链接分为不同操作系统如下,点击链接跳转下载页面&#xff1a; windows操作系统JDK下载链接(按住键盘ctrl键单击链接即可)&#xff1a; 链接7天有效&#xff0c;有需要的评论区找我哈 通过网盘分享的文件&#xff1a;jdk-8u271-windows-x64.exe 链…

人工智能如何将人机交互提升到新水平

随着人工智能模型在语音识别和合成、文本处理和多模态性方面的卓越表现&#xff0c;终极语音用户界面可能很快就会无处不在。欢迎来到雲闪世界。 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 那是一个典型的星期五下午&#xff0c;我们刚刚结束了一个…

如何用wireshark分析找出url接口和param参数???

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

Linux 内核源码分析---IPv6 数据包

IPv6是英文“Internet Protocol Version 6”&#xff08;互联网协议第6版&#xff09;的缩写&#xff0c;是互联网工程任务组&#xff08;IETF&#xff09;设计的用于替代IPv4的下一代IP协议&#xff0c;其地址数量号称可以为全世界的每一粒沙子编上一个地址。 由于IPv4最大的…

Tapd敏捷开发平台的使用心得

Tapd敏捷开发平台的使用心得 一、Tapd 简介 TAPD(Tencent Agile Product Development),腾讯敏捷产品研发平台行业领先的敏捷协作方案,贯穿敏捷产品研发生命周期的一站式服务,了解敏捷如下图 二、几个核心模块概念 需求迭代缺陷故事墙前期项目需求的管理,可以按类别建…

22AP10 SS524 平替 海思HI3521DV200 可提供开发资料

22AP10 是针对多路高清/超高清&#xff08;1080p/4M/5M/4K&#xff09;DVR 产品应用开发的新一代专 业 SoC 芯片。22AP10 集成了 ARM Cortex-A7 四核处理器和性能强大的图像分析工具 推理引擎&#xff0c;支持多种智能算法应用。同时&#xff0c;22AP10 还集成了多路 MIPI …

【可兼容的】protobuf、streamlit、transformers、icetk、cpm_kernels版本号

搞大模型训练的工作不可避免地需要很多库&#xff0c;但是非常讨厌的事情是这些库动不动就不兼容。最近在做文本分类训练的时候又遇到了这个问题&#xff0c;为了避免后面再安装包的时候把我之前的环境破坏了&#xff0c;所以特地来记录一下&#xff1a;protobuf、streamlit、t…

排序算法见解(2)

1.快速排序 1.1基本思想&#xff1a; 快速排序是通过一趟排序将待排序的数据分割成独立的两部分&#xff0c;其中一部分的所有数据都比另一部分的所有数据都要小&#xff0c;然后再按此方法对这两部分数据分别进行快速排序&#xff0c;整个排序过程可以递归进行&#xff0c;以…

解决Springboot项目Maven下载依赖速度慢的问题

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

智能客服系统:提升客户体验与企业效率的革命性工具

在当今数字化时代&#xff0c;企业与客户之间的互动方式正在迅速改变。智能客服系统作为一种新兴技术&#xff0c;不仅在提高客户满意度方面发挥着重要作用&#xff0c;还能够大大提高企业的运营效率。本文将详细探讨智能客服系统的工作原理、优势、实施步骤以及未来发展趋势。…

AI的未来已来:GPT-4商业应用带来的无限可能

随着人工智能技术的快速发展&#xff0c;OpenAI于2023年3月15日发布了多模态预训练大模型GPT-4&#xff0c;这一里程碑式的进步不仅提升了AI的语言处理能力&#xff0c;还拓展了其应用范围。本文将深入探讨GPT-4的技术进步、商业化进程、用户体验改善、伦理和社会影响&#xff…