分布式事务 Seata 与链路追踪 SkyWalking 全解析

一、事务基础认知

1.1 本地事务

事务是数据库操作的基本单元,用于保证一组 SQL 语句的原子性执行 ------ 要么全部成功执行并提交,要么全部失败回滚。

数据库事务核心遵循 ACID 原则:

  • 原子性(Atomicity):事务是最小执行单位,不可拆分
  • 一致性(Consistency):事务执行前后数据状态始终合法
  • 隔离性(Isolation):并发事务间相互隔离,互不干扰
  • 持久性(Durability):事务提交后,数据修改永久生效
本地事务的实现方式
  1. 数据库原生控制
sql 复制代码
START TRANSACTION
  -- 保存订单
  INSERT INTO tb_order (item_id, num) VALUES (1, 2);
  -- 扣减库存
  UPDATE tb_item SET num = num - 2 WHERE id = 1;
-- 失败回滚/成功提交
ROLLBACK; -- COMMIT;
  1. JDBC 编程式事务
java 复制代码
Connection conn = getConnection();
try {
    conn.setAutoCommit(false); // 关闭自动提交
    Statement stmt = conn.createStatement();
    stmt.executeUpdate("INSERT INTO tb_order ...");
    stmt.executeUpdate("UPDATE tb_item ...");
    conn.commit(); // 手动提交
} catch (Exception e) {
    conn.rollback(); // 异常回滚
} finally {
    conn.close();
}
  1. Spring 声明式事务(AOP)
java 复制代码
@Transactional // 事务注解
public void insertOrder(TbOrder tbOrder) {
    // 保存订单
    tbOrderMapper.insertSelective(tbOrder);
    // 扣减库存
    itemService.updateItem(tbOrder.getItemId(), tbOrder.getNum());
}

1.2 分布式事务

随着微服务架构普及,业务操作往往跨多个服务 / 数据库,此时本地事务无法保证全局一致性,分布式事务应运而生。

分布式事务产生场景
  1. 跨微服务调用:订单服务调用库存服务扣减库存,跨 JVM 进程
  2. 跨数据库实例:单体应用操作多个 MySQL 实例(用户库 + 订单库)
  3. 多服务操作同一数据库:不同服务持有独立数据库连接,仍会产生分布式事务
分布式事务的核心问题

传统本地事务在分布式场景下失效:

java 复制代码
@Transactional
public void insertOrder(TbOrder tbOrder) {
    // 本地保存订单(成功)
    tbOrderMapper.insertSelective(tbOrder);
    // 远程调用扣减库存(成功)
    itemServiceFeign.updateItem(tbOrder.getItemId(), tbOrder.getNum());
    // 模拟异常,本地事务回滚,但库存已扣减
    int a = 6 / 0;
}

二、分布式事务解决方案 - Seata

2.1 Seata 核心概念

Seata(Simple Extensible Autonomous Transaction Architecture)是阿里开源的分布式事务框架,目标是让分布式事务使用像本地事务一样简单。

核心组件
  • TC(Transaction Coordinator):事务协调器,维护全局事务状态,协调提交 / 回滚
  • TM(Transaction Manager):事务管理器,定义全局事务范围,发起全局提交 / 回滚
  • RM(Resource Manager):资源管理器,管理本地事务,向 TC 注册分支事务
Seata 事务模式
模式 一致性 可用性 业务侵入 适用场景
XA 强一致 金融核心场景
TCC 最终一致 定制化业务
AT 最终一致 通用业务(默认)
SAGA 最终一致 最高 长事务场景

2.2 AT 模式工作流程(重点)

AT 模式是 Seata 默认推荐的无侵入方案,分为两个阶段:

一阶段(本地事务提交)
  1. 解析 SQL,提取表名、条件、修改内容
  2. 查询前镜像:执行 SQL 前的数据状态
sql 复制代码
SELECT id, name, num FROM tb_item WHERE id = 1;
  1. 执行业务 SQL:UPDATE tb_item SET num = 98 WHERE id = 1;
  2. 查询后镜像:执行 SQL 后的数据状态
  3. 插入回滚日志到undo_log表,记录前后镜像与 SQL 信息
  4. 向 TC 注册分支事务,申请全局锁
  5. 提交本地事务,上报事务状态给 TC
二阶段
  • 回滚 :TC 下发回滚指令,RM 根据undo_log中的前镜像生成回滚 SQL,恢复数据
  • 提交 :TC 下发提交指令,RM 删除undo_log日志(异步执行,性能高)

2.3 Seata 环境搭建

1. 下载与解压

bash:

复制代码
# 下载地址:https://github.com/seata/seata/releases
tar -zxvf seata-server-1.4.2.tar.gz -C /usr/local/
2. 配置注册中心(Nacos)

修改conf/registry.conf

properties:

复制代码
registry {
  type = "nacos"
  nacos {
    application = "seata-server"
    serverAddr = "192.168.204.129:8848"
    group = "SEATA_GROUP"
    cluster = "default"
  }
}
config {
  type = "nacos"
  nacos {
    serverAddr = "192.168.204.129:8848"
    group = "SEATA_GROUP"
    dataId = "seataServer.properties"
  }
}
3. 配置数据源(Nacos 配置中心)

添加配置项seataServer.properties

properties:

复制代码
store.mode=db
store.db.dbType=mysql
store.db.url=jdbc:mysql://192.168.61.130:3306/seata?useSSL=false
store.db.user=root
store.db.password=1111
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.lockTable=lock_table
4. 创建 TC 数据库表
sql 复制代码
CREATE DATABASE seata;
USE seata;

-- 全局事务表
CREATE TABLE `global_table` (
  `xid` VARCHAR(128) NOT NULL,
  `status` TINYINT NOT NULL,
  PRIMARY KEY (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 分支事务表
CREATE TABLE `branch_table` (
  `branch_id` BIGINT NOT NULL,
  `xid` VARCHAR(128) NOT NULL,
  PRIMARY KEY (`branch_id`),
  KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 锁表
CREATE TABLE `lock_table` (
  `row_key` VARCHAR(128) NOT NULL,
  `branch_id` BIGINT NOT NULL,
  PRIMARY KEY (`row_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5. 启动 Seata Server

bash:

复制代码
cd /usr/local/seata/bin
./seata-server.sh -h 192.168.61.133 -p 8091

2.4 微服务整合 Seata

1. 依赖引入(所有参与事务的服务)
XML 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
2. 配置文件(application.yml)

yaml:

复制代码
seata:
  registry:
    type: nacos
    nacos:
      server-addr: 192.168.204.129:8848
      group: SEATA_GROUP
      application: seata-server
  tx-service-group: seata-demo
  service:
    vgroup-mapping:
      seata-demo: default
3. 业务改造(事务发起方)
java 复制代码
@GlobalTransactional // 替换@Transactional,开启全局事务
public void insertOrder(TbOrder tbOrder) {
    // 保存订单(本地事务)
    tbOrderMapper.insertSelective(tbOrder);
    // 远程调用扣减库存(分支事务)
    itemServiceFeign.updateItem(tbOrder.getItemId(), tbOrder.getNum());
    // 异常时全局回滚
    int a = 6 / 0;
}
4. 效果验证
  • 异常发生时,订单插入和库存扣减会全局回滚
  • 无异常时,所有分支事务正常提交

三、链路追踪 SkyWalking

3.1 为什么需要 SkyWalking

微服务架构下,一个请求可能经过多个服务调用(如:用户下单→订单服务→库存服务→支付服务),传统日志监控无法清晰追踪请求全链路:

  • 定位慢查询 / 异常节点困难
  • 无法直观看到服务间依赖关系
  • 缺乏全链路性能指标分析

3.2 SkyWalking 核心定位

SkyWalking 是国产开源 APM(应用性能管理)工具,由吴晟开源并纳入 Apache 基金会,核心能力:

  • 分布式追踪:追踪请求全链路,定位异常节点
  • 性能指标分析:监控服务 / 接口响应时间、QPS 等
  • 服务依赖分析:可视化展示服务间调用关系
  • 告警监控:自定义阈值告警,及时发现问题

3.3 SkyWalking 核心优势

  1. 低侵入:支持无代码侵入的探针式接入(Agent)
  2. 多语言支持:Java/Go/Python 等主流语言
  3. 多数据源适配:支持监控 Elasticsearch/MySQL 等中间件
  4. 云原生友好:适配 Docker/K8s 等容器化环境

四、实操总结

  1. 分布式事务:Seata 通过 TC/TM/RM 架构,以 AT 模式实现无侵入的分布式事务管控,解决微服务跨服务 / 跨库的数据一致性问题。
  2. 链路追踪:SkyWalking 弥补了微服务架构下全链路监控的空白,是定位性能瓶颈、排查分布式问题的核心工具。
  3. 技术选型建议
    • 金融级强一致性场景:Seata XA 模式
    • 通用业务场景:Seata AT 模式
    • 微服务全链路监控:SkyWalking + Prometheus + Grafana

通过 Seata 解决分布式事务一致性问题,结合 SkyWalking 实现全链路可观测,可有效保障微服务架构的稳定性与可维护性。

相关推荐
ezreal_pan8 小时前
Kafka Docker 部署持久化避坑指南:解决重启后 Cluster ID 不匹配问题
分布式·docker·zookeeper·容器·kafka·devops
小张小张爱学习9 小时前
Kafka面试题
分布式·kafka
fengxin_rou11 小时前
RabbitMQ安装教程:windows本地安装和docker部署
java·分布式·后端·rabbitmq
星辰_mya11 小时前
分布式消息领域的“深水区”问题
分布式
juniperhan11 小时前
Flink 系列第20篇:Flink SQL 语法全解:从 DDL 到 DML,窗口、聚合、列转行一网打尽
大数据·数据仓库·分布式·sql·flink
小旭952712 小时前
分布式事务 Seata 详解 + 链路追踪 SkyWalking 实战
java·分布式·后端·信息可视化·skywalking
ElevenS_it18813 小时前
日志在哪里找?分布式环境下日志采集断裂的5个排查路径
运维·网络·分布式
Jackyzhe13 小时前
从零学习Kafka:生产者分区机制
分布式·学习·kafka
以为你知道啊14 小时前
mini-job极简分布式延迟任务队列 — 基于 Redis,支持 Cron 周期任务、异步协程和多执行器
redis·分布式·junit