分布式事务指南
最后更新:2026-01-15
分布式事务是指在分布式系统中,涉及多个节点、多个服务或多个数据库的操作需要作为一个整体事务来保证其一致性和完整性的机制。
想象你在电商平台购物:
这些服务可能部署在不同的服务器上,使用不同的数据库。如何保证这些操作要么全部成功,要么全部失败?这就是分布式事务要解决的核心问题。
| 特性 | 单机事务 | 分布式事务 |
|---|---|---|
| 数据位置 | 单一数据库 | 多个数据库/服务 |
| 事务管理 | 本地事务管理器 | 全局事务协调器 |
| 一致性保证 | ACID 强一致性 | 通常是最终一致性 |
| 性能影响 | 较小 | 较大(网络通信) |
| 实现复杂度 | 低 | 高 |
| 故障场景 | 相对简单 | 复杂(网络分区、节点故障等) |
在分布式系统中,如何保证多个节点的数据在事务执行前后保持一致?
问题场景:
网络通信可能出现的问题:
提出者:Eric Brewer(2000年)
核心内容:在分布式系统中,以下三个特性无法同时完全满足,最多只能同时满足其中两项:
所有节点在同一时间看到的数据是一致的。
示例:用户在节点 A 写入数据后,立即从节点 B 读取,能读到最新数据。
系统在任何时候都能响应用户的请求(非错误响应)。
示例:即使部分节点故障,系统仍然能够处理请求。
系统能够容忍网络分区故障,即使节点间无法通信,系统仍能继续运行。
示例:网络故障导致集群分裂为两部分,系统仍能继续提供服务。
一致性 (C)
/\
/ \
/ \
/ CA \
/ \
/----------\
/ /\ /\ \
/ / \/ \ \
/ / CP AP \ \
/ / \ \
/ /____________\ \
可用性(A) 分区容错性(P)
在实际应用中:
注意:分区容错性(P)在分布式系统中通常是必须的,因此实际上是在 C 和 A 之间权衡。
BASE 理论是对 CAP 定理中一致性和可用性权衡的结果,是 Basically Available、Soft State 和 Eventually Consistent 的缩写。
系统在出现故障时,允许损失部分可用性,但保证核心功能可用。
具体表现:
允许系统中的数据存在中间状态,并认为该中间状态不会影响系统整体可用性。
具体表现:
系统中所有的数据副本,在经过一段时间的同步后,最终能达到一致的状态。
具体表现:
| 特性 | ACID | BASE |
|---|---|---|
| 目标 | 强一致性 | 高可用性 |
| 一致性 | 强一致性 | 最终一致性 |
| 事务模型 | 刚性事务 | 柔性事务 |
| 性能 | 较低 | 较高 |
| 复杂度 | 相对简单 | 相对复杂 |
| 适用场景 | 金融、支付核心业务 | 互联网高并发场景 |
| 典型代表 | 传统关系型数据库 | NoSQL、微服务 |
2PC 是最经典的分布式事务协议,将事务处理分为两个阶段:
阶段一:准备阶段(Prepare Phase / Vote Phase)
协调者 (Coordinator)
|
|-- PREPARE --> 参与者1 (Participant 1)
| |
| v
| [执行事务但不提交]
| |
| v
| [写入 undo/redo 日志]
| |
| v
| YES/NO (投票)
|
|-- PREPARE --> 参与者2 (Participant 2)
| |
| v
| YES/NO (投票)
|
v
[收集所有投票]
流程:
阶段二:提交阶段(Commit Phase)
协调者
|
v
[所有参与者都返回 YES?]
|
|-- YES --> 发送 COMMIT 给所有参与者
| |
| v
| [提交事务]
| |
| v
| [释放资源]
| |
| v
| [返回 ACK]
|
|-- NO --> 发送 ROLLBACK 给所有参与者
|
v
[回滚事务]
|
v
[释放资源]
|
v
[返回 ACK]
流程:
场景1:协调者在准备阶段故障
场景2:协调者在提交阶段故障
场景3:参与者在准备阶段故障
场景4:网络分区导致部分参与者未收到提交指令
为了解决 2PC 的阻塞问题和单点故障问题,3PC 引入了超时机制和CanCommit 阶段。
阶段一:CanCommit 阶段(询问阶段)
协调者
|
|-- CanCommit? --> 参与者1
| |
| v
| [检查资源]
| |
| v
| YES/NO
|
|-- CanCommit? --> 参与者2
|
v
YES/NO
流程:
阶段二:PreCommit 阶段(预提交阶段)
协调者
|
v
[所有参与者返回 YES?]
|
|-- YES --> 发送 PreCommit 给所有参与者
| |
| v
| [执行事务但不提交]
| |
| v
| [写入 undo/redo 日志]
| |
| v
| [返回 ACK]
|
|-- NO --> 发送 Abort 给所有参与者
|
v
[中止事务]
流程:
阶段三:DoCommit 阶段(提交阶段)
协调者
|
v
[所有参与者返回 ACK?]
|
|-- YES --> 发送 DoCommit 给所有参与者
| |
| v
| [提交事务]
| |
| v
| [返回 ACK]
|
|-- NO/TIMEOUT --> 发送 Abort 给所有参与者
|
v
[回滚事务]
关键改进:超时机制
| 特性 | 2PC | 3PC |
|---|---|---|
| 阶段数 | 2 个阶段 | 3 个阶段 |
| 超时机制 | 无 | 有 |
| 阻塞时间 | 较长 | 较短 |
| 单点故障影响 | 严重 | 较小 |
| 实现复杂度 | 低 | 高 |
| 网络通信次数 | 较少 | 较多 |
| 性能 | 较差 | 更差 |
| 一致性保证 | 强一致 | 强一致(理论上) |
XA 协议是由 X/Open 组织提出的分布式事务规范,定义了事务管理器(TM)与资源管理器(RM)之间的接口。
应用程序 (Application)
|
v
事务管理器 (TM - Transaction Manager)
|
|-- XA 接口
|
v
资源管理器 (RM - Resource Manager)
| | |
v v v
数据库1 数据库2 消息队列
角色:
xa_start // 开始事务分支
xa_end // 结束事务分支
xa_prepare // 准备提交
xa_commit // 提交事务
xa_rollback // 回滚事务
xa_recover // 恢复未完成的事务
XA 协议基于 2PC 实现:
1. 应用程序调用 TM 开启全局事务
2. TM 为每个 RM 分配事务分支 ID
3. 应用程序通过 TM 操作各个 RM
4. TM 向所有 RM 发送 xa_prepare
5. 所有 RM 返回成功后,TM 发送 xa_commit
6. 如有 RM 失败,TM 发送 xa_rollback
-- 会话1:参与者1
XA START 'xid1';
UPDATE account SET balance = balance - 100 WHERE id = 1;
XA END 'xid1';
XA PREPARE 'xid1';
-- 等待协调者指令
XA COMMIT 'xid1'; -- 或 XA ROLLBACK 'xid1';
-- 会话2:参与者2
XA START 'xid2';
UPDATE account SET balance = balance + 100 WHERE id = 2;
XA END 'xid2';
XA PREPARE 'xid2';
-- 等待协调者指令
XA COMMIT 'xid2'; -- 或 XA ROLLBACK 'xid2';
TCC 是一种侵入式的分布式事务解决方案,将业务操作拆分为三个阶段:Try、Confirm、Cancel。
Try 阶段(尝试)
Confirm 阶段(确认)
Cancel 阶段(取消)
TCC 协调器
|
+---------------+---------------+
| | |
v v v
服务A 服务B 服务C
| | |
[Try 阶段] [Try 阶段] [Try 阶段]
| | |
成功 成功 成功
| | |
+---------------+---------------+
|
v
[所有 Try 都成功?]
|
+-----------+-----------+
| |
YES NO
| |
v v
[Confirm 阶段] [Cancel 阶段]
| |
确认所有服务 取消所有服务
场景:账户 A 向账户 B 转账 100 元
Try 阶段:
// 账户 A:冻结 100 元
boolean tryDeduct(String accountId, BigDecimal amount) {
// 1. 检查账户余额是否足够
Account account = accountDao.findById(accountId);
if (account.getBalance().compareTo(amount) < 0) {
return false;
}
// 2. 冻结金额(不扣减余额,增加冻结金额)
account.setFrozenAmount(account.getFrozenAmount().add(amount));
accountDao.update(account);
return true;
}
// 账户 B:预增加 100 元(记录待确认金额)
boolean tryAdd(String accountId, BigDecimal amount) {
Account account = accountDao.findById(accountId);
account.setPendingAmount(account.getPendingAmount().add(amount));
accountDao.update(account);
return true;
}
Confirm 阶段:
// 账户 A:扣减余额,释放冻结金额
void confirmDeduct(String accountId, BigDecimal amount) {
Account account = accountDao.findById(accountId);
account.setBalance(account.getBalance().subtract(amount));
account.setFrozenAmount(account.getFrozenAmount().subtract(amount));
accountDao.update(account);
}
// 账户 B:增加余额,清除待确认金额
void confirmAdd(String accountId, BigDecimal amount) {
Account account = accountDao.findById(accountId);
account.setBalance(account.getBalance().add(amount));
account.setPendingAmount(account.getPendingAmount().subtract(amount));
accountDao.update(account);
}
Cancel 阶段:
// 账户 A:释放冻结金额
void cancelDeduct(String accountId, BigDecimal amount) {
Account account = accountDao.findById(accountId);
account.setFrozenAmount(account.getFrozenAmount().subtract(amount));
accountDao.update(account);
}
// 账户 B:清除待确认金额
void cancelAdd(String accountId, BigDecimal amount) {
Account account = accountDao.findById(accountId);
account.setPendingAmount(account.getPendingAmount().subtract(amount));
accountDao.update(account);
}
1. 幂等性
Confirm 和 Cancel 操作必须支持幂等,因为可能会重试。
实现方式:
2. 空回滚
Cancel 操作可能在 Try 操作还未执行时就被调用(网络延迟)。
解决方案:
3. 悬挂
Try 超时后执行了 Cancel,但 Try 请求最终还是到达了。
解决方案:
Saga 模式是一种长事务解决方案,将全局事务拆分为一系列本地事务,每个本地事务都有对应的补偿操作。
T1 → T2 → T3 → T4 → ... → Tn
如果 Tn 失败,则执行:
Cn-1 → Cn-2 → ... → C2 → C1
1. 事件驱动编排(Event Choreography)
各服务之间通过事件进行通信,无中央协调器。
服务A → [事件] → 服务B → [事件] → 服务C
| | |
v v v
执行T1 执行T2 执行T3
| | |
+--------失败-----+ |
| |
v |
[发布补偿事件] |
| |
v v
执行C1 执行C2
特点:
2. 命令协调(Command Orchestration)
使用中央协调器来管理 Saga 流程。
Saga 协调器
|
+--------+--------+
| | |
v v v
服务A 服务B 服务C
| | |
T1 T2 T3
| | |
成功 成功 失败
| | |
+--------+--------+
|
v
[触发补偿]
|
+--------+--------+
| |
v v
C2 C1
特点:
业务流程:
正向操作:
T1: 创建订单(订单状态:待支付)
T2: 扣减库存
T3: 处理支付
T4: 发送通知(订单状态:已完成)
补偿操作:
C1: 取消订单(订单状态:已取消)
C2: 恢复库存
C3: 退款处理
C4: 发送取消通知
执行流程示例:
// Saga 协调器
public class OrderSaga {
public void executeOrder(Order order) {
try {
// T1: 创建订单
orderService.createOrder(order);
try {
// T2: 扣减库存
inventoryService.deductInventory(order.getItems());
try {
// T3: 处理支付
paymentService.processPayment(order.getPaymentInfo());
// T4: 发送通知
notificationService.sendNotification(order);
} catch (Exception e) {
// C3: 退款(如果支付失败)
// 支付失败不需要退款
// C2: 恢复库存
inventoryService.restoreInventory(order.getItems());
// C1: 取消订单
orderService.cancelOrder(order.getId());
throw e;
}
} catch (Exception e) {
// C2: 恢复库存(如果扣减库存失败)
// 库存扣减失败不需要恢复
// C1: 取消订单
orderService.cancelOrder(order.getId());
throw e;
}
} catch (Exception e) {
// C1: 取消订单(如果创建订单失败)
// 创建订单失败不需要取消
throw e;
}
}
}
使用状态机管理 Saga 流程:
[开始]
|
v
[创建订单] ----失败----> [结束]
|
成功
|
v
[扣减库存] ----失败----> [取消订单] --> [结束]
|
成功
|
v
[处理支付] ----失败----> [恢复库存] --> [取消订单] --> [结束]
|
成功
|
v
[发送通知]
|
v
[结束]
1. 补偿操作设计
补偿操作不是简单的回滚,而是业务上的”反向操作”。
示例:
2. 补偿的幂等性
补偿操作可能会被多次调用,必须保证幂等性。
3. 补偿的顺序
补偿操作通常按照正向操作的逆序执行。
4. 补偿失败处理
通过在本地数据库中引入消息表,将业务操作和消息记录放在同一个本地事务中,确保两者的原子性。
┌─────────────────────────────────┐
│ 服务 A │
│ ┌───────────────────────────┐ │
│ │ 本地数据库 │ │
│ │ ┌─────────────┐ │ │
│ │ │ 业务表 │ │ │
│ │ └─────────────┘ │ │
│ │ ┌─────────────┐ │ │
│ │ │ 消息表 │ │ │
│ │ │ (msg_id, │ │ │
│ │ │ content, │ │ │
│ │ │ status) │ │ │
│ │ └─────────────┘ │ │
│ └───────────────────────────┘ │
│ | │
│ v │
│ ┌───────────────┐ │
│ │ 消息发送服务 │ │
│ └───────────────┘ │
└─────────────┼───────────────────┘
|
v
消息队列 (MQ)
|
v
┌─────────────┴───────────────────┐
│ 服务 B │
│ ┌───────────────┐ │
│ │ 消息消费者 │ │
│ └───────────────┘ │
└─────────────────────────────────┘
步骤 1:服务 A 执行本地事务
BEGIN TRANSACTION;
-- 业务操作
UPDATE account SET balance = balance - 100 WHERE id = 1;
-- 插入消息记录
INSERT INTO message_table (msg_id, content, status, create_time)
VALUES ('msg_001', '{"accountId": 1, "amount": 100}', 'PENDING', NOW());
COMMIT;
步骤 2:定时任务扫描消息表
@Scheduled(fixedRate = 1000) // 每秒执行一次
public void scanMessageTable() {
// 查询待发送的消息
List<Message> messages = messageDao.findByStatus("PENDING");
for (Message message : messages) {
try {
// 发送到消息队列
mqProducer.send(message.getContent());
// 更新消息状态为已发送
message.setStatus("SENT");
messageDao.update(message);
} catch (Exception e) {
log.error("发送消息失败: {}", message.getMsgId(), e);
// 重试逻辑(可以增加重试次数字段)
}
}
}
步骤 3:服务 B 消费消息
@RabbitListener(queues = "order.queue")
public void handleMessage(String messageContent) {
try {
// 解析消息
TransferInfo info = JSON.parseObject(messageContent, TransferInfo.class);
// 执行业务操作(幂等处理)
accountService.addBalance(info.getAccountId(), info.getAmount());
// 返回 ACK,消息从队列中删除
} catch (Exception e) {
log.error("处理消息失败: {}", messageContent, e);
// 返回 NACK,消息重新入队或进入死信队列
}
}
1. 本地事务保证原子性
业务操作和消息插入在同一个数据库事务中,要么都成功,要么都失败。
2. 消息发送可靠性
3. 消息消费幂等性
消息可能会被重复消费,必须保证幂等:
public void addBalance(String accountId, BigDecimal amount, String msgId) {
// 检查消息是否已处理
if (processedMessageDao.exists(msgId)) {
log.info("消息已处理,跳过: {}", msgId);
return;
}
// 执行业务操作
Account account = accountDao.findById(accountId);
account.setBalance(account.getBalance().add(amount));
accountDao.update(account);
// 记录已处理的消息
processedMessageDao.insert(msgId);
}
4. 消息表清理
定期清理已成功处理的历史消息。
最大努力通知是一种非可靠消息的解决方案,允许在通知过程中出现失败,但通过重试机制尽最大努力确保通知的送达。
┌──────────┐
│ 服务 A │
│(事务发起) │
└─────┬────┘
|
v
[执行本地事务]
|
v
[立即发送通知] ───────────┐
| |
v v
[成功?] ┌──────────┐
| │ 服务 B │
YES │ NO │(事务参与) │
| | └─────┬────┘
v v |
[结束] [记录失败] v
| [处理通知]
v |
[定时重试] ─────────────┘
|
v
[达到最大重试次数?]
|
YES │ NO
| |
v v
[人工介入]
[继续重试]
方式 1:主动通知 + 重试
public class NotificationService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private NotificationLogDao notificationLogDao;
// 发送通知
public void sendNotification(String url, String data) {
int maxRetries = 5;
int retryCount = 0;
boolean success = false;
while (retryCount < maxRetries && !success) {
try {
// 发送 HTTP 请求
ResponseEntity<String> response = restTemplate.postForEntity(url, data, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
success = true;
// 记录成功日志
notificationLogDao.insertLog(url, data, "SUCCESS", retryCount);
}
} catch (Exception e) {
retryCount++;
log.warn("通知发送失败,第 {} 次重试", retryCount, e);
// 指数退避策略
try {
Thread.sleep((long) Math.pow(2, retryCount) * 1000);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
if (!success) {
// 记录失败日志,等待人工处理
notificationLogDao.insertLog(url, data, "FAILED", retryCount);
}
}
}
方式 2:被动查询
服务 B 主动查询服务 A 的事务状态。
// 服务 B 定期查询
@Scheduled(fixedRate = 60000) // 每分钟查询一次
public void queryTransactionStatus() {
List<PendingTransaction> pendingTxs = pendingTxDao.findAll();
for (PendingTransaction tx : pendingTxs) {
try {
// 查询服务 A 的事务状态
String status = restTemplate.getForObject(
"http://serviceA/transaction/status?txId=" + tx.getTxId(),
String.class
);
if ("SUCCESS".equals(status)) {
// 执行本地事务
processTransaction(tx);
// 删除待处理记录
pendingTxDao.delete(tx.getId());
} else if ("FAILED".equals(status)) {
// 删除待处理记录
pendingTxDao.delete(tx.getId());
}
// 如果是 PENDING,继续等待
} catch (Exception e) {
log.error("查询事务状态失败: {}", tx.getTxId(), e);
}
}
}
1. 固定间隔重试
重试1:立即
重试2:5秒后
重试3:10秒后
重试4:15秒后
2. 指数退避
重试1:1秒后
重试2:2秒后
重试3:4秒后
重试4:8秒后
重试5:16秒后
3. 自定义策略
重试1:立即
重试2:1分钟后
重试3:5分钟后
重试4:30分钟后
重试5:2小时后
支付结果通知
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户端 │ │ 商户系统 │ │ 支付平台 │
└─────┬────┘ └─────┬────┘ └─────┬────┘
| | |
| 发起支付 | |
|─────────────────────|────────────────────>|
| | |
| | [处理支付]
| | |
| 支付成功 | |
|<────────────────────|─────────────────────|
| | |
| | [通知商户] |
| |<────────────────────|
| | |
| | [回复 ACK] |
| |─────────────────────>|
| | |
| | [如果未收到 ACK,重试通知]
| |<────────────────────|
| | |
| [商户主动查询] |
| |─────────────────────>|
| | |
| | [返回支付状态] |
| |<────────────────────|
1976年:Jim Gray 提出事务的概念
1979年:提出两阶段提交协议(2PC)
1991年:X/Open 提出 XA 协议
1987年:三阶段提交协议(3PC)提出
2000年:CAP 定理
2002年:CAP 定理的证明
2008年:BASE 理论
2012年:Saga 模式的流行
2014年:TCC 模式的广泛应用
2019年:Seata 开源
分布式事务向云原生演进
事件驱动架构(EDA)的兴起
《The Transaction Concept: Virtues and Limitations》
《Concurrency Control and Recovery in Database Systems》
《Brewer’s Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services》
《CAP Twelve Years Later: How the “Rules” Have Changed》
《The Part-Time Parliament》
《Paxos Made Simple》
《In Search of an Understandable Consensus Algorithm》
《Sagas》
《Eventually Consistent》
《Designing Data-Intensive Applications》(数据密集型应用系统设计)
《Distributed Systems》
涉及的服务:
典型场景:
用户下单流程:
1. 订单服务:创建订单
2. 库存服务:扣减库存
3. 优惠券服务:核销优惠券
4. 支付服务:处理支付
5. 积分服务:增加积分
6. 物流服务:创建物流单
推荐方案:
涉及的操作:
推荐方案:
涉及的操作:
推荐方案:
特点:
推荐方案:
场景:
推荐方案:
场景:
推荐方案:
涉及的服务:
推荐方案:
涉及的操作:
推荐方案:
涉及的操作:
推荐方案:
特点:
推荐方案:
挑战:
推荐方案:
| 方案 | 一致性 | 性能 | 复杂度 | 侵入性 | 适用场景 |
|---|---|---|---|---|---|
| XA/2PC | 强一致 | 低 | 中 | 低 | 金融核心业务、对一致性要求极高 |
| 3PC | 强一致 | 低 | 高 | 低 | 很少使用,理论意义大于实践 |
| TCC | 最终一致 | 高 | 高 | 高 | 高并发、对性能要求高、业务可控 |
| Saga | 最终一致 | 高 | 中 | 中 | 长事务、流程复杂、跨系统 |
| 本地消息表 | 最终一致 | 中 | 低 | 低 | 异步通知、对实时性要求不高 |
| 最大努力通知 | 最终一致 | 高 | 低 | 低 | 跨系统通知、允许消息丢失 |
1. 对一致性要求极高(金融核心业务)
2. 高并发场景(电商秒杀)
3. 长事务场景(订单处理流程)
4. 异步通知场景
5. 跨系统通知(支付回调)
1. 单体应用 + 多数据库
2. 微服务架构
3. 云原生架构
1. 团队经验不足
2. 团队经验丰富
3. 使用成熟框架
简介:阿里巴巴开源的分布式事务解决方案
特性:
官网:https://seata.io/
GitHub:https://github.com/seata/seata
示例项目:
简介:华为开源的分布式事务解决方案
特性:
官网:https://servicecomb.apache.org/
GitHub:https://github.com/apache/servicecomb-pack
简介:高性能分布式事务 TCC 框架
特性:
GitHub:https://github.com/dromara/hmily
简介:基于 TCC 补偿型事务的分布式事务框架
特性:
GitHub:https://github.com/liuyangming/ByteTCC
简介:阿里巴巴开源的柔性事务解决方案
特性:
GitHub:https://github.com/QNJR-GROUP/EasyTransaction
基于 Spring Cloud + Seata 实现电商系统的分布式事务:
项目结构:
mall-system
├── order-service (订单服务)
├── inventory-service (库存服务)
├── payment-service (支付服务)
├── account-service (账户服务)
└── seata-server (Seata 服务端)
GitHub 参考项目:
实现一个基于 TCC 的转账系统:
核心接口:
public interface AccountTccService {
// Try: 冻结金额
boolean tryDeduct(String accountId, BigDecimal amount);
// Confirm: 确认扣款
boolean confirmDeduct(String accountId, BigDecimal amount);
// Cancel: 取消扣款
boolean cancelDeduct(String accountId, BigDecimal amount);
}
实现一个订单处理的 Saga 流程:
流程设计:
创建订单 → 扣减库存 → 处理支付 → 创建物流单
↓ ↓ ↓ ↓
取消订单 恢复库存 退款处理 取消物流
需要使用的场景:
不需要使用的场景:
2PC(XA):
3PC:
替代方案:
选择 TCC 的场景:
选择 Saga 的场景:
对比总结:
性能影响因素:
不同方案的性能对比:
优化建议:
幂等性的重要性:
实现方式:
-- 使用数据库唯一索引
CREATE UNIQUE INDEX idx_order_id ON orders(order_id);
// 只有在特定状态才能执行操作
if (order.getStatus() == OrderStatus.PENDING) {
order.setStatus(OrderStatus.PAID);
orderDao.update(order);
}
// 使用 Redis 分布式锁
String lockKey = "order:" + orderId;
if (redisLock.tryLock(lockKey)) {
try {
// 执行业务逻辑
processOrder(orderId);
} finally {
redisLock.unlock(lockKey);
}
}
// 使用雪花算法生成全局唯一 ID
String transactionId = snowflake.nextId();
// 每次操作都带上 transactionId
// 记录已处理的 transactionId
if (processedIds.contains(transactionId)) {
return; // 已处理,跳过
}
监控指标:
监控工具:
失败类型:
处理策略:
@Retryable(
value = {RemoteException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000, multiplier = 2)
)
public void processTransaction() {
// 业务逻辑
}
if (retryCount > MAX_RETRY) {
alertService.sendAlert("分布式事务失败", transactionId);
}
// 记录到异常表
exceptionDao.insert(new TransactionException(
transactionId,
"补偿失败",
errorMessage
));
设计原则:
实践建议:
关系说明:
实践建议:
测试类型:
测试工具:
参考资料:
提示:本文档持续更新中,如有问题或建议,欢迎反馈。