美文网首页
分布式事务解决方案

分布式事务解决方案

作者: 麦大大吃不胖 | 来源:发表于2020-12-27 10:53 被阅读0次

by shihang.mai

1. 事件表+定时任务+MQ

分布式事务-定时任务+MQ+事件表

事件表核心表结构

字段 备注
Id 主键
order_type 事件类型,例如派单
state 状态
content 发送到mq的数据,包括本表事件id

加入定时任务,是为了做补偿机制。过了零点,扫面前一天的数据,重新投放到mq即可。

当工单模块消费mq时,创建一样的一条记录到工单系统的事件表。即两个事件表一样的。这样为了做幂等处理。

需要做幂等原因:

  1. 当工单系统完成后返回ack,mq挂了,那么就会出现状态已完成,但是mq还是未消费成功。mq还会重试发送到工单系统

2. TXLCN-LCN

用在本身带事务的场景,如mysql

  • l-lock
  • c:confirm
  • n:notify

2.1 原理

lcn组件架构图


lcn组件

lcn原理图如下,摘自tx-lcn官网


lcn官方原理

图中第1 2 3步是第1阶段,第4步是第2阶段(lcn中的n,执行提交或者回滚)

lcn步骤

2.2 原理

核心类DataSourceAspect

@Aspect
@Component
@Slf4j
public class DataSourceAspect implements Ordered {

   private final TxClientConfig txClientConfig;

   private final DTXResourceWeaver dtxResourceWeaver;

   public DataSourceAspect(TxClientConfig txClientConfig, DTXResourceWeaver dtxResourceWeaver) {
       this.txClientConfig = txClientConfig;
       this.dtxResourceWeaver = dtxResourceWeaver;
   }


   @Around("execution(* javax.sql.DataSource.getConnection(..))")
   public Object around(ProceedingJoinPoint point) throws Throwable {
       return dtxResourceWeaver.getConnection(() -> (Connection) point.proceed());
   }


   @Override
   public int getOrder() {
       return txClientConfig.getResourceOrder();
   }


}

核心类LcnConnectionProxy

public class LcnConnectionProxy implements Connection {
  @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        connection.setAutoCommit(false);
    }

    @Override
    public void commit() throws SQLException {
        //connection.commit();
    }

    @Override
    public void rollback() throws SQLException {
        //connection.rollback();
    }

    @Override
    public void close() throws SQLException {
        //connection.close();
    }
}
  1. 利用aop,在getConnection的时候做一个环绕,返回一个Connection,这个Connection是LcnConnectionProxy。直接接管了原来的datasource的Connection。
  2. 在原本连接close阶段假释放,将请求和连接关系保存起来Map<请求Id,Connection>。那么进行第2阶段时就可以找回之前的操作的连接了。

代理datasource,保持请求和连接的对应

2.3 补偿

补偿机制,用到了redis。做了标记(那些Tx-client是异常的),做记录(通知的具体事项或者需要执行的sql)

2.4 核心步骤

TX-manager
mysql执行sql:
        jar包下有对应的创表sql
添加jar:
        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tm</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-txmsg-netty</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
添加配置:
        tx-lcn.manager.admin-key=xxx
        tx-lcn.logger.enabled=true
        tx-lcn.logger.driver-class-name=com.mysql.cj.jdbc.Driver
        tx-lcn.logger.jdbc-url=jdbc:mysql://localhost:3306/tx-manager?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
        tx-lcn.logger.username=xxx
        tx-lcn.logger.password=xxx
添加注解:
        启动类上@EnableTransactionManagerServer

TX-client
添加jar:
        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-txmsg-netty</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
添加配置:
        tx-lcn:
          client:
            manager-address: 127.0.0.1:8070
添加注解:
        启动类@EnableDistributedTransaction
        业务类@LcnTransaction

3. TXLCN-TCC

用在本身不带事务的场景,如redis

  • try
    检查网络连接、检查业务、隔离资源
  • confirm
    使用try阶段隔离的资源,进行真正事务提交。因为tcc引入补偿机制:重试和超时。因为有重试机制,必须幂等。而幂等操作肯定要一个唯一ID,即事务ID,相同事务ID,相同的事,即可以进行幂等操作。
  • cancel
    回滚

3.1 核心步骤

/**
* TX-manager TX-client的添加jar、配置、启动类注解都与lcn一致
*/
//业务类
    @Transactional(rollbackFor = Exception.class)
    @TccTransaction
    public String add(@RequestBody TblOrder bean){

        
        return "xxx";
    }

    public String confirmAdd(TblOrder bean){

        System.out.println("xxx ");
        return "xxx";
    }

    //用来保存第1阶段操作过的id,其中key为(机器-方法-时间戳)等能唯一表示的key
    private static Map<String,Integer> maps = new HashMap<>();

    public String cancelAdd(TblOrder bean){
        //自己做回滚逻辑
        return "xxx";
    }

4. seata

它有4种模式,分别是AT、TCC、SAGA、XA模式

seata中角色

  • TC(事务协调者)
  • TM(事务发起者,实际也是RM)
  • RM(资源管理者)

4.1 AT模式

以下有3个库,分别模拟正常流程和异常流程

seata-server global_table, lock_table , branch_table
a yw, undo_log
b yw, undo_log
seata-角色.png

正常流程

  1. 请求到达TM,TM向TC注册一个全局事务,获得一个全局锁,TC向seata-server的global_table插入一条数据
  2. 在TM执行自己业务逻辑时,向TC注册一个分支事务,TC向branch_table和lock_table各插入一条数据,TM获得一个本地锁,然后将业务数据插入a库的yw表和对应的undolog插入a库的undolog表,然后释放本地锁(不是删除库记录,这是容许其他线程竞争)
  3. TM调用RM,RM向TC注册一个分支事务,TC向branch_table和lock_table各插入一条数据,RM获得一个本地锁,然后将业务数据插入b库的yw表和对应的undolog插入b库的undolog表,然后释放本地锁(不是删除库记录,这是容许其他线程竞争)
  4. TM向TC发送commit,TC删除global_table、lock_table、branch_table记录,TC通知TM和RM提交,即通知它们分别删除自己的undo_log表记录

异常流程

  1. 请求到达TM,TM向TC注册一个全局事务,获得一个全局锁,TC向seata-server的global_table插入一条数据
  2. 在TM执行自己业务逻辑时,向TC注册一个分支事务,TC向branch_table和lock_table各插入一条数据,TM获得一个本地锁,然后将业务数据插入a库的yw表和对应的undolog插入a库的undolog表,然后释放本地锁(不是删除库记录,这是容许其他线程竞争)
  3. TM调用RM,RM向TC注册一个分支事务,TC向branch_table和lock_table各插入一条数据,RM获得一个本地锁,然后将业务数据插入b库的yw表和对应的undolog插入b库的undolog表,然后释放本地锁(不是删除库记录,这是容许其他线程竞争)
  4. 如果此时调用链上还有一个RM,那么重复3的步骤,但是其中发生了异常
  5. TM向TC发送roll back,TC通知TM和所有RM回滚,即通知它们分别执行自己的undo_log表记录,在执行undo_log前需要获取本地锁。然后TC删除global_table、lock_table、branch_table记录

4.2 TCC

4.2.1 空回滚

try未执行,执行cancel
解决:加事务控制表

字段 含义
tx_id 全局事务id
branch_id 分支id
state 状态(try、confirm、cancel)

执行cancel时,检查是否有try的记录,没的话进行空回滚

4.2.2 幂等

多次执行conform、cancel
解决:加事务控制表

字段 含义
tx_id 全局事务id
branch_id 分支id
state 状态(事务初始化、已提交、已回滚)

在执行前先检查库记录即可。执行过就不执行

4.2.3 悬挂

执行cancel在try之前
解决:加事务控制表

字段 含义
tx_id 全局事务id
branch_id 分支id
state 状态(事务初始化、已提交、已回滚)

cnacel的时候,如果原来没记录,执行空方法,再向里面插入一条已回滚记录,try执行的时候发现有已回滚记录,空try

相关文章

  • 分布式事务的解决方案

    本文从以下几个方面介绍分布式事务的解决方案: 为什么会有分布式事务分布式事务经典模型分布式事务解决方案 为什么会有...

  • 分布式事务

    目录 分布式事务解决方案 长事务: saga 短事务: 设计的时候尽量短事务,能不用分布式事务尽量不用,分布式事务...

  • 微服务中分布式事务解决方案

    分布式事务解决方案 1、阿里巴巴seata分布式事务 2、 京东ShardingSphere分布式事务 3、tcc...

  • 微服务 14:初探微服务分布式事务 - Seata

    1:什么是事务,什么是ACID 2:什么是分布式事务 3:分布式事务解决方案 4:Seata 分布式事务框架 5:...

  • 常用的分布式事务解决方案

    常用的分布式事务解决方案 再有人问你分布式事务,把这篇扔给他

  • seata AT模式

    描述 seata是分布式事务解决方案。分布式事务是包含若干分支事务的全局事务。如果各分支事务提交成功,则全局事务提...

  • 分布式事务解决方案

    分布式事务解决方案 分布式事务的主要解决方案 XA方案 - 两阶段提交方案 TCC方案 本地消息表 可靠信息最终一...

  • java分布式,最终一致性,java幂等问题分析

    分布式学习: 分布式常用的分布式事务解决方案介绍有多少种?基于 Redis 的分布式锁分布式简介关于分布式事务、两...

  • 分布式事务总结

    事务、分布式事务、Base、CAP不赘述。 业内场景的分布式事务解决方案有,2PC、3PCTCC(alipay)增...

  • 分布式事务(3)--seate

    Seate控制分布式事务:Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。...

网友评论

      本文标题:分布式事务解决方案

      本文链接:https://www.haomeiwen.com/subject/ldjinktx.html