微服务

felix.shao2025-06-22

微服务

1 分布式事务

分布式事务概述

 以下是有研究的事务介绍。

  • Spring Boot
    • JTA:内置功能,不需要特殊处理。
  • sample-atomiko:基于 Atomiko 实现多数据源数据库的分布式事务
  • Seata:基于 Seata 实现多节点分布式事务。
分布式事务解决方案
  • 技术方案
    • 基于 XA 协议(数据库层面)
      • 2PC、3PC
    • 基于补偿和最终一致性
      • AT
      • TCC
      • Saga
      • 本地消息
      • 消息队列
  • 实现方式
    • Seata
      • XA
      • AT
      • TCC
      • Saga
    • RocketMQ 等消息中间件
      • 消息队列
    • 本地消息表
      • 本地消息
2 PC
 2PC 概念

 2PC(Two-Phase Commit,两阶段提交)是一种经典的分布式事务协议,用于确保在分布式系统中所有参与者要么全部提交事务,要么全部回滚事务,从而保证数据的一致性。2PC 的参与角色如下。

  • 协调者(Coordinator):负责协调整个事务的提交或回滚。
  • 参与者(Participant):实际执行事务的各个节点/服务。
 2PC 执行流程

 2PC 执行流程分为 2 个阶段,如下。

  • 第一阶段:准备阶段(投票阶段)
    • 1 协调者发送准备请求:协调者向所有参与者发送 prepare 请求,询问是否可以提交事务
    • 2 参与者执行事务:每个参与者执行事务操作,但不真正提交
    • 3 参与者记录日志:参与者将事务信息写入日志(用于故障恢复)
    • 4 参与者响应准备结果:
      • 4.1 如果事务可以提交,返回 Yes(就绪)响应
      • 4.2 如果事务不能提交(如出现冲突或错误),返回 No(中止)响应
  • 第二阶段:提交阶段(执行阶段),根据第一阶段的投票结果,有两种情况
    • 情况 1:所有参与者都返回Yes
      • 1 协调者发送提交命令:协调者向所有参与者发送 commit 请求
      • 2 参与者完成提交:参与者正式提交事务,释放锁资源
      • 3 参与者发送确认:参与者向协调者发送 ack 确认
      • 4 协调者完成事务:收到所有参与者的 ack 后,协调者结束事务
    • 情况 2:任一参与者返回 No 或超时未响应
      • 1 协调者发送回滚命令:协调者向所有参与者发送 rollback 请求
      • 2 参与者执行回滚:参与者根据日志回滚事务,释放锁资源
      • 3 参与者发送确认:参与者向协调者发送 ack 确认
      • 4 协调者结束事务:收到所有参与者的ack后,协调者结束事务
 2PC 的优缺点
  • 优点
    • 强一致性:保证所有节点要么全部成功,要么全部失败
    • 简单易懂:协议流程清晰,易于理解和实现
  • 缺点
    • 同步阻塞:在准备阶段后,参与者会一直阻塞等待协调者的决定
    • 单点故障:协调者故障可能导致系统阻塞
    • 数据不一致风险:在第二阶段,如果部分参与者未收到 commit/rollback 命令,可能导致数据不一致
    • 性能开销:需要多次网络通信和日志写入,性能较低
3 PC
 3PC 概念

 3PC(Three-Phase Commit,三阶段提交)是分布式系统中用于保证事务原子性的一种协议,是 2PC(两阶段提交)的改进版本。它通过增加一个准备阶段来减少阻塞问题,提高了系统的可用性。

 3PC 执行流程

 3 PC 的 3 个阶段如下。

  • 第一阶段:CanCommit 阶段
    • 协调者行为
      • 1 向所有参与者发送 CanCommit 请求
      • 2 询问参与者是否可以执行事务提交
      • 3 等待参与者响应
    • 参与者行为
      • 1 检查自身状态(资源是否锁定、日志是否可写等)
      • 2 如果能够提交,返回 Yes 响应;否则返回 No 响应
  • 第二阶段:PreCommit 阶段,根据第一阶段的响应,协调者决定是否继续
    • 情况一:所有参与者返回 Yes
      • 协调者发送 PreCommit 请求
      • 参与者执行事务操作但不提交,记录 undo/redo 日志
      • 参与者返回 Ack 响应
    • 情况二:有参与者返回 No 或超时
      • 协调者发送 abort 请求
      • 参与者中断事务
  • 第三阶段:DoCommit 阶段
    • 正常提交流程:
      • 1 协调者收到所有 PreCommit 的 Ack 后,发送 DoCommit 请求
      • 2 参与者完成事务提交,释放资源
      • 3 参与者返回 HaveCommitted 响应
    • 中断流程:
      • 1 协调者没有收到所有 PreCommit 的 Ack
      • 2 协调者发送 abort 请求
      • 3 与者使用 undo 日志回滚事务
 3PC 和 2PC 的主要区别
  1. 增加 CanCommit 阶段:提前发现不可行的事务,减少资源锁定时间
  2. 超时机制:参与者在 PreCommit 阶段后如果长时间未收到协调者消息,会自动提交
  3. 减少阻塞:降低了协调者单点故障导致的长时间阻塞问题
 3PC 的优缺点
  • 优点
    • 相比 2PC 减少了阻塞时间
    • 通过预检查降低了资源浪费
    • 超时机制提高了系统可用性
  • 缺点
    • 实现复杂度高于 2PC
    • 网络通信次数增加
    • 仍然存在数据不一致的可能性(如网络分区时)
AT
 AT 概述

 AT(Auto Transaction)模式是 Seata 框架提出的无侵入分布式事务解决方案,基于两阶段提交(2PC)演进而来。其核心特点是:

  • 业务无侵入:不需要业务代码改造
  • 自动补偿:自动生成反向 SQL 实现回滚
  • 基于数据库本地事务:通过全局锁保证隔离性
 AT 整体架构
[TM] → [TC] ← [RM]
  │       │      │
  │       │      ├─ 阶段一:注册分支 + 提交本地事务
  │       │      └─ 阶段二:上报状态 + 异步清理
  • TM (Transaction Manager):定义全局事务边界(@GlobalTransactional)
  • TC (Transaction Coordinator):事务协调器(Seata Server)
  • RM (Resource Manager):资源管理器,管理分支事务
 AT 执行流程(正常提交)
  • 阶段一:执行与提交
    • 1 TM 开启全局事务
      • TM 向 TC 申请 XID(全局事务 ID)
      • 示例:@GlobalTransactional 注解的方法被调用
    • 2 RM 执行本地事务
      • 业务 SQL 执行前,RM 拦截 SQL:
        • 解析 SQL 语义(INSERT/UPDATE/DELETE)
        • 查询前置镜像(before image)
      • 执行业务 SQL
      • 查询后置镜像(after image)
      • 生成 undo_log 记录(包含前后镜像)
      • 提交本地事务(业务 SQL 和 undo_log 在同一个本地事务)
    • 3 注册分支事务
      • RM 向 TC 注册分支事务,关联 XID
      • 获取相关数据的全局锁
  • 阶段二:全局提交
    • 1 TM 通知 TC 提交
      • 所有分支事务执行成功后,TM向TC发起全局提交
    • 2 TC 异步清理
      • TC 异步删除各 RM 的 undo_log 记录
      • 释放全局锁
 AT 执行流程(异常回滚)
  • 阶段一:执行与提交
    • 同正常流程
  • 阶段二:全局回滚
    • 1 TM 通知 TC 回滚
      • 任一分支事务失败时,TM 向 TC 发起全局回滚
    • 2 RM 执行补偿
      • TC 通知各 RM 回滚
      • RM 查询 undo_log 记录
      • 校验脏写(对比当前数据与后置镜像)
      • 根据 before image 生成反向 SQL 执行回滚
      • 删除 undo_log 记录
      • 释放全局锁
 AT 核心机制

 全局锁设计

  • 避免其他事务修改正在处理的数据
  • 实现方式:SELECT FOR UPDATE 或 TC 维护的内存锁

 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,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
);

 数据镜像生成规则。

  • INSERT:before image 为空,after image 为插入数据
  • UPDATE:before image 为更新前数据,after image 为更新后数据
  • DELETE:before image 为删除前数据,after image 为空
 AT 特点
  • 优势
    • 零侵入:无需业务代码改造
    • 高性能:本地事务一阶段立即提交
    • 自动补偿:无需手动编写反向逻辑
    • 支持多语言:通过 SQL 解析实现跨语言支持
  • 限制
    • 仅支持关系型数据库
    • 隔离级别为读未提交(需业务容忍脏读)
    • UPDATE/DELETE 操作需有主键
    • 高并发场景全局锁可能成为瓶颈
TCC
 TCC 概念

 TCC(Try-Confirm-Cancel)是一种补偿型分布式事务解决方案,通过业务逻辑层面的设计来实现最终一致性。它将一个完整的业务逻辑拆分为三个操作。

  • Try:预留业务资源
  • Confirm:确认执行业务操作
  • Cancel:取消业务操作并释放资源
 TCC 执行流程

 TCC 的三个阶段。

  • 尝试阶段:Try 阶段。
    • 目的:完成所有业务检查,预留必要的业务资源
    • 执行流程
      • 1 事务协调器向所有参与者发送 Try 请求
      • 2 各参与者执行:
        • 2.1 检查业务一致性条件(如库存是否充足)
        • 2.2 预留资源(如冻结库存、预扣金额)
        • 2.3 记录事务日志(用于后续 Confirm 或 Cancel)
      • 3 参与者返回执行结果(成功/失败)
    • 特点
      • 此阶段不会真正完成业务操作
      • 所有操作必须幂等(重复调用效果相同)
  • 确认阶段:Confirm 阶段
    • 前提条件: 所有参与者的 Try 阶段都执行成功
    • 执行流程
      • 1 事务协调器向所有参与者发送 Confirm 请求
      • 2 各参与者执行:
        • 2.1 使用 Try 阶段预留的资源完成实际业务操作
        • 2.2 提交事务(如扣减实际库存、完成支付)
        • 2.3 更新事务状态为"已完成"
      • 3 参与者返回执行结果
    • 特点
      • 此阶段操作必须幂等
      • 默认 Confirm 一定会成功(因为 Try 已预留资源)
  • 取消阶段:Cancel 阶段
    • 触发条件:任一参与者的 Try 阶段执行失败
    • 执行流程
      • 1 事务协调器向所有参与者发送 Cancel 请求
      • 2 各参与者执行:
        • 2.1 释放 Try 阶段预留的资源(如解冻库存、返还预扣金额)
        • 2.2 更新事务状态为"已取消"
      • 3 参与者返回执行结果
    • 特点
      • 参与者返回执行结果
      • 需要处理 Try 阶段可能部分成功的情况

 TCC 事务管理器的工作流程。

    1. 开始全局事务:生成全局事务 ID
    1. 调用 Try 阶段:按业务逻辑顺序调用各服务的 Try 接口
    1. 决策阶段:
    • 所有 Try 成功 → 进入 Confirm 阶段
    • 任一 Try 失败 → 进入 Cancel 阶段
  • 4 执行 Confirm/Cancel:根据决策结果调用相应接口
  • 5 记录事务状态:持久化事务最终状态
 TCC 模式的特点
  • 优点
    • 高可用性:没有全局锁,减少资源锁定时间
    • 高性能:Try 阶段完成后,Confirm 通常很快
    • 灵活性:业务可定制化程度高
    • 最终一致性:保证系统最终一致
  • 缺点
    • 开发复杂度高:每个业务都需要实现三个接口
    • 业务侵入性强:需要改造现有业务逻辑
    • 一致性风险:Confirm/Cancel 可能失败(需重试机制)
 TCC 与 2PC/3PC 的关键区别
  • 实现层面
    • 2PC/3PC:数据库/资源管理器层面
    • TCC:业务应用层面
  • 锁定范围
    • 2PC/3PC:锁定整个资源
    • 2PC/3PC:锁定整个资源
  • 事务持续时间
    • 2PC/3PC:整个事务期间都持有锁
    • TCC:Try 阶段后即可释放大部分资源
Saga
 Saga 概述

 Saga 是一种长事务解决方案,核心思想是将一个长事务拆分为多个本地事务,每个本地事务都有对应的补偿操作。Saga 特别适合以下场景:

  • 长时间运行的业务过程(分钟/小时级)
  • 跨多个服务的业务流
  • 无法实现资源锁定的系统
 Saga 的两种实现方式
  • 1 协同式(Choreography)
    • 通过事件驱动架构实现
    • 各服务监听上游事件并触发本地事务
    • 无中心协调器,服务间直接通信
  • 2 编排式(Orchestration)
    • 通过中心协调器(Orchestrator)控制流程
    • 协调器按顺序调用各服务并处理异常
    • 更易维护和监控(推荐方式)
 Saga 核心执行流程(编排式)
  1. 正常流程
[协调器] → [服务A:事务T1] → [服务B:事务T2] → [服务C:事务T3] → 完成
  • 1 协调器开始 Saga 事务
  • 2 依次调用各服务的正向操作(T1, T2, T3...)
  • 3 所有正向操作成功则事务完成
  1. 异常回滚流程
[协调器] → [服务A:T1] → [服务B:T2失败] → [服务B:C2] → [服务A:C1] → 终止
  • 1 当某个正向操作(如T2)失败时:
  • 2 协调器按反向顺序调用已成功服务的补偿操作(C2, C1...)
  • 3 所有补偿完成后事务终止
 Saga 关键设计要素
  • 1 补偿操作要求
    • 1.1 幂等性:可重复执行不影响结果
    • 1.2 可交换性:补偿顺序不影响最终状态
    • 1.3 可丢弃性:补偿成功后不再需要保留历史
  • 2 事务日志记录,示例日志如下
  • 3 异常处理机制
    • 3.1 超时重试:对暂时性故障自动重试
    • 3.2 人工干预:无法自动恢复时告警
    • 3.3 最终一致性:允许短暂不一致但最终一致
 Saga 特点
  • 优势
    • 无长期资源锁定:适合长事务场景
    • 高可用性:部分服务不可用时仍可推进
    • 业务灵活性:可组合异构系统
    • 可扩展性:易于添加新服务节点
  • 挑战
    • 补偿逻辑复杂:需要设计完善的补偿机制
    • 调试困难:分布式环境问题定位复杂
    • 弱隔离性:可能出现脏读(需业务容忍)
本地消息表

 简单的整理下,流程仅供参考,说明简单了。

  1. 创建一个本地消息表
  2. 本地服务执行本地事务并提交,将要发送的消息插入本地消息表中
  3. 通过定时任务扫描未发送的消息,通过消息队列发送消息
  4. 另一个服务接收消息执行事务,执行失败就重试,多次重试失败就放入死信队列,人工干预处理。
消息队列

 简单的整理下,流程仅供参考,说明简单了。

  1. 使用 RocketMQ 实现事务消息,将消息发送和本地事务的执行实现强一致性。
  2. 如果发送消息成功,另一个服务接收消息执行事务,执行失败就重试,多次重试失败就添加到本地消息表中,人工干预处理。
atomikos
 1. atomikos 应用场景
  1. 基于XA协议的多资源协调 (完全支持)
    ✅ 跨数据库节点 (MySQL、Oracle等支持XA的数据库)
    ✅ 数据库+消息队列 (如ActiveMQ等支持XA的消息中间件)
    ✅ 同架构跨服务节点 (所有服务使用相同Atomikos配置)

  2. 不支持的分布式场景
    ❌ 跨微服务的事务 (服务间RPC调用)
    ❌ 非XA资源的事务 (如MongoDB、Redis等不支持XA协议的NoSQL)
    ❌ 跨异构系统的事务 (不同编程语言/技术栈的系统)

 2. 快速上手

 有如下两个使用方式,详见示例代码 sample-atomikosopen in new window

  1. 基于原有多数据源支持改造上手。
    (1) 引入 maven 依赖。
    (2) 配置 DataSource。见 FirstDbConfig。

  2. 简单的快速上手示例。
     见 AtomikosQuickTest main 方法。

Last Updated 6/23/2025, 9:08:47 PM
ON THIS PAGE