news 2026/2/14 7:44:56

架构视角下的分布式事务(二):柔性事务与最终一致性方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
架构视角下的分布式事务(二):柔性事务与最终一致性方案

微服务架构下的分布式事务解决方案

第一篇内容:

  1. 什么是分布式事务(定义、产生背景、核心难点)
  2. 什么时候使用(跨库、跨服务场景、电商案例)
  3. 理论基石(CAP 权衡、CP vs AP)
  4. 强一致性方案(2PC 详解与缺陷、3PC 的改进与局限)
    架构视角下的分布式事务(一):核心理论与强一致性方案

第二篇内容:

  1. TCC 补偿型事务(Try-Confirm-Cancel 详解、三大异常处理)
  2. 可靠消息最终一致性(基于 MQ + 本地消息表方案)
  3. Saga 长事务模式(编排式 vs 协同式、ACD 模型)
  4. 全文总结与选型建议

TCC - 补偿型事务

TCC

TCC是一种位于应用层(Business Layer)的分布式事务解决方案。与 2PC/XA 依赖数据库层面的锁不同,TCC 将资源管理的粒度上移到业务逻辑中,通过业务代码来实现资源的预留、确认和释放。

它本质上是一种柔性事务(Flexible Transaction),遵循BASE 理论,追求最终一致性。可以将其视为**“应用层的两阶段提交”**。


TCC 执行流程

TCC 模式将一个业务操作拆分为三个接口:TryConfirmCancel

三阶段详解

  1. Try 阶段(业务检查 & 资源预留):

    • 核心逻辑:完成所有的业务一致性检查(Business Check),并预留必须的业务资源(Reserve Resources)。
    • 特点:只做“准”操作,不做“实”操作。
    • 示例:转账场景中,不是直接扣钱,而是检查余额是否充足,并将转账金额从“可用余额”移动到“冻结字段”。
  2. Confirm 阶段(业务确认):

    • 核心逻辑:真正执行业务,不做任何业务检查(Try 阶段已做过)。只使用 Try 阶段预留的资源。
    • 特点:满足幂等性。如果 Try 成功,Confirm 必须成功。如果执行失败,事务管理器会进行重试,直到成功。
  3. Cancel 阶段(业务取消):

    • 核心逻辑:释放 Try 阶段预留的业务资源。
    • 特点:满足幂等性。这是“反向操作”或“补偿操作”。

TCC 的三大关键技术挑战

在分布式网络环境下,TCC 必须处理三种棘手的异常情况,这要求业务代码具备极高的鲁棒性。

1. 幂等性
  • 场景:无论是 Confirm 还是 Cancel,都可能因为网络超时(Packet Loss)导致事务管理器重复发送请求。
  • 要求:业务接口必须保证重复调用产生的结果是一样的
  • 实现:通常通过引入“事务记录表”或利用“状态机”判断,如果该事务 ID 已经处理过,则直接返回成功,不重复扣款或回滚。
2. 空回滚
  • 场景:事务管理器调用 Service A 的Try请求,但因为网络故障,请求未到达Service A,或者 Service A 还没处理完就抛错了。此时事务管理器判定 Try 失败,触发全局回滚,向 Service A 发送Cancel请求。
  • 问题:Service A 根本没收到过Try,却收到了Cancel
  • 要求:Cancel接口必须能识别这种情况,允许“未 Try 先 Cancel”,直接返回成功,什么都不做。
  • 实现:查询事务记录表,如果没找到对应的 Try 记录,说明是空回滚。
3. 资源悬挂
  • 场景:事务管理器调用Try,发生严重的网络拥塞(超时)。事务管理器判定超时,发出CancelCancel先到达并执行成功(处理了空回滚逻辑)。随后,迟到的Try请求终于到达了。
  • 问题:如果执行了这个迟到的Try,资源就被预留(冻结)了。但因为全局事务已经结束(已回滚),永远不会有ConfirmCancel来释放这笔资源。这笔资源就被永久“悬挂”锁死了。
  • 要求:Try方法执行前,必须检查该事务 ID 是否已经执行过Cancel。如果已回滚,拒绝执行Try
  • 实现:利用“防悬挂记录”或检查事务状态,若发现已有 Cancel 记录,则 Try 抛出异常或直接返回。

TCC 的优缺点深度分析

优点:性能与灵活性
  1. 高并发(High Concurrency):
    • TCC 不使用数据库层面的全局排他锁(Global Lock)。
    • 锁的粒度在业务层(如行记录的状态字段),只会阻塞该条数据的特定状态变更,不会阻塞整个表的访问。
    • 资源锁定时间短,不占用数据库连接。
  2. 细粒度控制:
    • 可以针对不同的服务实现不同的补偿逻辑,支持异构数据库。
缺点:高开发成本与代码侵入
  1. 强代码侵入性:
    • Service 层的每个接口都必须改造。原本的一个 update 接口,现在需要拆解为 Try、Confirm、Cancel 三个逻辑。
    • 业务逻辑与事务逻辑耦合严重。
  2. 开发成本高昂 :
    • 一个业务链路如果有 5 个服务,就需要写 15 个接口方法。
    • 开发人员必须深刻理解 TCC 原理,手动处理预留资源的逻辑(如给数据库表加frozen_amount字段)。
  3. 复杂度极高:
    • 必须完美处理上述的幂等、空回滚、悬挂三大异常,否则会导致数据错乱或资金损失。这通常需要依赖成熟的 TCC 框架(如 Seata TCC 模式, ByteTCC, Himly)来辅助实现。

可靠消息最终一致性

可靠消息最终一致性

可靠消息最终一致性是一种基于BASE 理论的分布式事务解决方案,通常归类为AP(可用性优先)架构。

它通过引入消息队列 (Message Queue, MQ)进行异步解耦,将长事务拆分为本地事务和下游事务。其核心目标是保证:只要上游服务(生产者)的本地事务提交成功,下游服务(消费者)最终一定能收到消息并执行成功。

该方案通常采用“本地消息表 (Transactional Outbox Pattern)”“事务消息 (Transactional Messaging)”来实现。


架构流程图 (基于本地消息表模式)

此图展示了如何保证“本地事务执行”与“消息发送”的原子性,以及下游如何保证最终成功。


核心机制深度解析

1. 上游原子性:本地消息表

这是解决“业务执行”与“发送MQ”非原子性问题的经典方案。

  • 问题背景:先发 MQ 后写库,库写失败了怎么办?先写库后发 MQ,MQ 发失败了怎么办?
  • 解决方案:
    • 利用本地数据库的ACID 特性
    • 在同一个本地事务中,既写入业务数据(如:生成订单),也写入一条消息记录(状态:待发送)
    • 结果:业务数据和消息记录要么同时存在,要么同时回滚。

2. 消息投递:可靠性保证

即使消息落库了,还需要保证投递到 MQ。

  • 轮询/投递 (Poller):一个独立的线程或定时任务不断扫描“待发送”的消息,投递到 MQ。
  • 状态翻转:投递成功后,将本地消息状态更新为**“已发送”**。
  • 兜底机制:如果更新状态失败,或者 MQ 没收到,定时任务下次还会扫描到这条消息进行重发(这就要求下游必须幂等)。

3. 下游消费:重试与死信

下游服务可能因为网络抖动、数据库繁忙等原因暂时失败。

  • ACK 机制 (Acknowledgement):只有业务逻辑完全执行成功后,消费者才向 MQ 发送确认(ACK)。
  • 自动重试策略:如果消费者抛出异常或超时未 ACK,MQ 会根据策略(如指数退避算法:1s, 5s, 10s…)重新投递消息。
  • 死信队列 (Dead Letter Queue, DLQ):当重试次数达到阈值(如 16 次)仍未成功,MQ 将该消息移入 DLQ。这意味着发生了人工介入级别的故障(如代码 Bug 或数据错误),系统会自动告警,由运维或开发手动处理。

4. 关键防御:幂等性设计 (Idempotency)

由于网络的不确定性和 MQ 的重试机制,消息被重复投递是必然发生的 (At-Least-Once Delivery)。下游必须保证重复消费不会导致业务错误。

  • 唯一键约束 (Unique Key):利用数据库的唯一索引(如order_idmessage_id)防止插入重复记录。
  • 去重表 (Deduplication Table):专门建立一张表记录已处理的message_id。消费前先查表,若存在则直接 ACK 并返回。
  • 状态机控制 (State Machine):
    • UPDATE orders SET status = 'PAID' WHERE id = 100 AND status = 'UNPAID';
    • 利用UPDATE语句的行锁和条件判断(CAS 乐观锁思想),确保状态只能流转一次。

方案优缺点总结

  • 优点:

    • 解耦 (Decoupling):生产者不需要关心消费者是否在线,发完消息即可结束。
    • 削峰填谷 (Load Leveling):能够承受高并发冲击。
    • 代码侵入性较低:相比 TCC,不需要拆分 Try/Confirm/Cancel,主要逻辑集中在消息发送和消费端。
  • 缺点:

    • 实时性较差:依赖异步投递,存在一定延迟。
    • 运维复杂度:需要维护独立的消息服务、定时任务和消息表清理机制。
    • 不支持回滚:一旦消息发出,如果下游一直失败(进入死信),上游通常无法自动回滚,只能通过“人工补偿”或生成“反向消息”来修正数据。

Saga模式 - 长事务补偿

Saga 模式

Saga 模式是一种处理分布式系统中长运行事务(Long-Running Transaction)的解决方案。它放弃了传统 ACID 中强一致性和隔离性的要求,转而采用BASE 理论

Saga 将一个全局的分布式事务拆分为一系列有序的本地事务 (Local Transaction)。每个本地事务更新数据库并发布事件触发下一个本地事务。

核心逻辑包含两个部分:

  1. 正向操作 (Transaction, T):正常的业务逻辑执行。
  2. 补偿操作 (Compensation, C):当某个步骤失败时,用于撤销之前操作的逻辑。

Saga 的两种主要实现模式

  1. 编排式 (Orchestration):

    • 引入一个中心化的SEC (Saga Execution Coordinator)
    • 协调器负责指挥:“A 执行完告诉我,我再通知 B;如果 B 失败,我通知 A 执行补偿”。
    • 特点:可视化流畅,状态机逻辑清晰,便于排查问题。
  2. 协同式 (Choreography):

    • 没有中心协调器,服务之间通过事件 (Event)驱动。
    • 服务 A 完成后发消息,服务 B 监听消息并执行。
    • 特点:耦合度极低,在业务流程混乱时难以追踪。

编排式 (Orchestration)是目前更主流、更推荐的选择


Saga 执行流程图 (基于编排器模式)

下图展示了 Saga 在遇到故障时,如何通过反向补偿来回滚事务。

假设业务流程是:扣减库存 (T1)->创建订单 (T2)->支付扣款 (T3)
场景:T1, T2 成功,但 T3 失败。

流程详解:

  1. 正向执行:依次执行 T1, T2。每个事务执行完立即提交本地数据库事务,锁资源被释放。
  2. 故障触发:执行到 T3 时发生错误(如余额不足)。
  3. 反向补偿:Saga 协调器(Orchestrator)感知到 T3 失败,开始按相反顺序调用已完成步骤的补偿操作。
    • 调用C2(T2 的补偿):将订单状态改为“已取消”或物理删除。
    • 调用C1(T1 的补偿):将扣减的库存加回去。
  4. 最终状态:数据库回滚到事务开始前的状态(数据语义上的一致)。

核心特性与缺陷深度解析

1. 缺失隔离性 - ACD 模型

这是 Saga 与 TCC/XA 最大的区别,也是其被诟病为“ACD”(缺了 I - Isolation)的原因。

  • 现象:在 Saga 执行过程中(例如 T1 刚提交,T2 还没开始),其他并发的业务请求可以看到T1 已经提交的数据。
  • 风险 - 脏读 (Dirty Read):如果 T1 扣了库存,此时用户 B 查询到了有库存。但随后 Saga 触发了补偿 C1 把库存加回去了。用户 B 看到的就是一个中间状态的数据。
  • 对策:业务设计上必须容忍“语义锁”或使用“冻结字段”策略,或者在业务层面做隔离(例如订单状态标记为“处理中”,对用户不可见)。

2.补偿的复杂性

“撤销”往往比“做”更难。

  • 逻辑难写:发送邮件的 T 操作,其 C 操作无法“撤回邮件”,只能“发送一封更正邮件”。
  • 重试机制:补偿操作C1本身也可能失败(例如网络断了)。Saga 框架必须保证补偿操作无限重试直到成功(这就要求人工介入死信队列作为最后的兜底)。

3. 必须幂等

由于网络环境的不稳定性,Saga 协调器可能会重复触发正向操作(T)或补偿操作(C)。

  • 要求:C1执行一次和执行 N 次,效果必须完全一样(例如:库存 = 库存 + 1,必须改为:如果流水号不存在则库存+1)。

总结

Saga 是一种**“先提交,后补偿”的模式。
它牺牲了隔离性(Isolation),换取了
长事务场景下的高并发与低延迟**(因为没有长周期的数据库锁)。适用于业务流程长、跨系统多、且允许短暂数据不一致的场景。

全文总结与选型指南

分布式事务是微服务架构中绕不开的挑战。从早期的数据库层面的2PC/XA,到后来应用层面的TCC、Saga,技术演进的核心逻辑始终是在“一致性 (Consistency)”“可用性/性能 (Availability/Performance)”之间寻找平衡点。

1. 技术演进脉络

  • 从刚性到柔性:传统的2PC/3PC追求 ACID 的强一致性,但因同步阻塞导致性能低下,不适应互联网高并发场景。因此,基于 BASE 理论的柔性事务(TCC、MQ、Saga)应运而生,它们允许数据在短时间内不一致,但保证最终一致。
  • 从数据库层到业务层:事务管理的控制权逐渐从数据库(DB Lock)上移至业务代码(Business Logic)。虽然这增加了开发的复杂度(如处理幂等、空回滚),但也带来了极大的性能提升和灵活性。

2. 核心选型

在做架构决策时,可以参考以下优先级:

  1. 首选策略:避免分布式事务

    • 如果可以通过合理的微服务拆分(领域模型调整)或数据分片策略,将操作限制在同一个数据库内,利用本地事务解决,那是最高效的。
  2. 资金/核心业务:强一致性 (Seata AT / 2PC)

    • 场景:银行转账、企业内部 ERP、数据准确性要求极高的核心链路。
    • 理由:必须保证数据时刻一致,不能容忍中间状态,且并发量通常可控。
  3. 高并发互联网业务:最终一致性 (MQ / TCC)

    • 场景 1 (高并发、解耦):电商下单后发货、积分发放、推送通知。
      • 推荐:可靠消息最终一致性 (MQ)。实现解耦,削峰填谷。
    • 场景 2 (强实时、细粒度控制):支付扣款、库存扣减(需立即反馈结果)。
      • 推荐:TCC。虽然代码侵入大,但能提供最高的性能和控制力。
  4. 长链路复杂业务:Saga 模式

    • 场景:旅游预订(机票+酒店+租车)、跨境物流链。
    • 推荐:Saga (编排式)。流程长、参与者多,不需要强隔离性,侧重于流程的可视化管理和补偿机制。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/12 15:06:44

基于SpringBoot+Vue的web项目申报系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】

摘要 随着信息技术的快速发展,传统的手工申报管理模式已无法满足现代企事业单位对高效、便捷、透明化管理的需求。项目申报管理系统作为一种信息化工具,能够有效解决申报流程繁琐、数据管理混乱、审批效率低下等问题。该系统通过数字化手段实现项目申报、…

作者头像 李华
网站建设 2026/2/9 16:39:47

当问卷告别 “凭经验设计”:宏智树 AI 重构科研测量的精准逻辑

当问卷告别 “凭经验设计”:宏智树 AI 重构科研测量的精准逻辑 你是否有过这样的困惑?花费数月设计的问卷,回收数据后却发现变量相关性微弱,研究假设无法验证;严格按照模板制作的量表,在特定样本群体中信度…

作者头像 李华
网站建设 2026/2/13 7:37:21

【限时揭秘】工业质检Agent精度提升的3个非公开训练技巧

第一章:工业质检Agent精度提升的核心挑战在现代智能制造体系中,工业质检Agent作为自动化质量控制的关键组件,其检测精度直接影响产品良率与生产效率。然而,在实际部署过程中,精度提升面临多重技术与工程挑战。数据质量…

作者头像 李华
网站建设 2026/2/7 19:55:14

基于SpringBoot的墙绘产品展示交易平台的设计与实现(11516)

有需要的同学,源代码和配套文档领取,加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码(前后端源代码SQL脚本)配套文档(LWPPT开题报告)远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华