分布式事务---Seata

分布式问题

单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证。

Seata 是什么?

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

Seata能干什么?

  • 分布式事务处理过程的一ID+三组件模型:
Transaction ID XID 全局唯一的事务ID
Transaction Coordinator(TC) 事务协调器:维护全局事务的运行状态,负责协调并驱动事务的提交或回滚
Transaction Manager(TM ) 事务管理器:控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议
Resource Manager(RM) 资源管理器:控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交或回滚

AT 模式

前提

  • 基于支持本地 ACID 事务的关系型数据库。
  • Java 应用,通过 JDBC 访问数据库。

整体机制

  • 两阶段提交协议的演变:
    • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
    • 二阶段:
      • 提交异步化,非常快速地完成。
      • 回滚通过一阶段的回滚日志进行反向补偿。

写隔离

  • 一阶段本地事务提交前,需要确保先拿到 全局锁 。
  • 拿不到 全局锁 ,不能提交本地事务。
  • 拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。

读隔离

  • 在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。

TCC 模式

  • 一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:

    • 一阶段 prepare 行为
    • 二阶段 commit 或 rollback 行为
  • 根据两阶段行为模式的不同,我们将分支事务划分为 Automatic (Branch) Transaction Mode 和 Manual (Branch) Transaction Mode.

  • AT 模式基于 支持本地 ACID 事务 的 关系型数据库:

    • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
    • 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
    • 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
  • 相应的,TCC 模式,不依赖于底层数据资源的事务支持:

    • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
    • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
    • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
  • 所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

Saga 模式

  • Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

适用场景

  • 业务流程长、业务流程多
  • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

优势

  • 一阶段提交本地事务,无锁,高性能
  • 事件驱动架构,参与者可异步执行,高吞吐
  • 补偿服务易于实现

缺点

  • 不保证隔离性

实例

用例

  • 用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:
    • 仓储服务:对给定的商品扣除仓储数量。
    • 订单服务:根据采购需求创建订单。
    • 帐户服务:从用户帐户中扣除余额。

架构图

在这里插入图片描述

仓储服务

public interface StorageService {

    /**
     * 扣除存储数量
     */
    void deduct(String commodityCode, int count);
}

订单服务

public interface OrderService {

    /**
     * 创建订单
     */
    Order create(String userId, String commodityCode, int orderCount);
}

帐户服务

public interface AccountService {

    /**
     * 从用户账户中借出
     */
    void debit(String userId, int money);
}

主要业务逻辑

public class BusinessServiceImpl implements BusinessService {

    private StorageService storageService;

    private OrderService orderService;

    /**
     * 采购
     */
    public void purchase(String userId, String commodityCode, int orderCount) {

        storageService.deduct(commodityCode, orderCount);

        orderService.create(userId, commodityCode, orderCount);
    }
}
public class OrderServiceImpl implements OrderService {

    private OrderDAO orderDAO;

    private AccountService accountService;

    public Order create(String userId, String commodityCode, int orderCount) {

        int orderMoney = calculate(commodityCode, orderCount);

        accountService.debit(userId, orderMoney);

        Order order = new Order();
        order.userId = userId;
        order.commodityCode = commodityCode;
        order.count = orderCount;
        order.money = orderMoney;

        // INSERT INTO orders ...
        return orderDAO.insert(order);
    }
}

SEATA 的分布式交易解决方案

在这里插入图片描述

  • 我们只需要使用一个 @GlobalTransactional 注解在业务方法上
    @GlobalTransactional
    public void purchase(String userId, String commodityCode, int orderCount) {
        ......
    }

你知道的越多,你不知道的越多。
有道无术,术尚可求,有术无道,止于术。
如有其它问题,欢迎大家留言,我们一起讨论,一起学习,一起进步

发布了193 篇原创文章 · 获赞 116 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40722827/article/details/105161929