02.支付中分布式事务
TCC
(银行转账
高一致性)Try:
冻结资金
、生成订单、预授权支付Confirm:
扣款
、增加余额、确认支付Cancel:解冻资金、取消订单、退款
设计要点:幂等性、超时机制、日志记录
SAGA
(电商
最终一致性)子事务:创建订单、扣减库存、支付
补偿操作:失败时按逆序退款、恢复库存、取消订单
设计要点:幂等性、日志记录、超时机制
总结:TCC 提供强一致性,SAGA 支持最终一致性,适用于不同场景
# 01.分布式事务解决方案
- 设计一个分布式事务解决方案时,主要目标是确保系统中
不同服务间的操作
可以在事务失败或中断时保持一致性
- 比如支付系统,涉及多个子系统(如订单、账户、支付渠道等),选择合适的分布式事务模式非常关键
# 1、TCC模式
适用场景:银行转账、证券交易等
Try 阶段:预先占用资源(如冻结账户金额、生成支付记录)
Confirm 阶段:确认支付完成,提交所有事务操作(如扣款、记录支付成功状态)
Cancel 阶段:如果任何步骤失败,取消操作并释放资源(如解冻资金)
注:TCC 的优势是能够提供较好的数据一致性,但在业务逻辑复杂的场景中,Cancel 操作的设计会较为复杂
# 1)Try
预留资源
检查资源并预留,确保后续操作可以执行
① 冻结转出账户金额
BEGIN TRANSACTION; UPDATE account SET balance = balance - 100, frozen_amount = frozen_amount + 100 WHERE account_id = 123; COMMIT;
1
2
3
② 生成唯一订单号,标记为“处理中”
③ 通知支付渠道准备扣款授权
,支付渠道返回预授权结果(成功或失败)- 如果所有操作
成功
,进入Confirm 阶段
- 如果任何操作
失败
,进入Cancel 阶段
- 如果所有操作
# 2)Confirm
提交事务
- 正式提交事务,完成资源操作
# 1.从冻结金额中扣除转账金额
UPDATE account SET frozen_amount = frozen_amount - 100 WHERE account_id = 123;
# 2.增加转入账户金额
UPDATE account SET balance = balance + 100 WHERE account_id = 456;
# 3.将订单状态从“处理中”改为“已完成”
UPDATE transfer_order SET status = 'completed' WHERE order_id = 'order123';
# 4.支付渠道确认扣款
# POST /payment/confirm
{
"order_id": "order123",
"amount": 100
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 所有操作成功,事务完成
- 如果任何操作失败,需记录日志并人工干预
# 3)Cancel
回滚事务
- 释放 Try 阶段预留的资源,回滚操作
# 1.将冻结金额返还到可用余额
UPDATE account SET balance = balance + 100, frozen_amount = frozen_amount - 100 WHERE account_id = 123;
# 2.将订单状态改为“已取消”
UPDATE transfer_order SET status = 'cancelled' WHERE order_id = 'order123';
# 3.通知支付渠道取消扣款授权
# POST /payment/cancel
{
"order_id": "order123",
"amount": 100
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 所有操作
成功
,资源释放,系统恢复到初始状态
- 如果任何操作
失败
,需记录日志并人工干预
# 4)设计要点
- 幂等性
- 每个阶段的操作需支持幂等性,确保
重复调用不会产生副作用
- 例如,Confirm 和 Cancel 操作需
根据订单状态判断是否已执行
- 每个阶段的操作需支持幂等性,确保
- 超时机制
- 为 Try 阶段
设置超时时间
,超时后自动进入 Cancel 阶段
- 为 Try 阶段
- 日志记录
- 记录每个阶段的详细操作日志,便于排查问题和数据恢复
# 2. SAGA 模式
# 1)子事务链条
按顺序执行多个子事务,确保业务流程完成
① 创建订单
- 生成订单,标记为“处理中”
INSERT INTO orders (order_id, user_id, product_id, quantity, status) VALUES ('order123', 123, 456, 2, 'pending');
1
2② 扣减库存复
UPDATE inventory SET stock = stock - 2 WHERE product_id = 456;
1③ 支付 调用支付渠道完成扣款
// POST /payment/process { "order_id": "order123", "amount": 200 }
1
2
3
4
5如果所有子事务成功,流程完成
如果任何子事务失败,进入补偿阶段
# 2)补偿操作链条
按顺序回滚已完成的子事务,恢复系统状态
① 取消支付
:调用支付渠道退款// POST /payment/refund { "order_id": "order123", "amount": 200 }
1
2
3
4
5
② 恢复库存
将库存数量加回③ 将订单状态改为“已取消”
所有补偿操作成功,系统恢复到初始状态
如果任何补偿操作失败,需记录日志并人工干预
# 3)设计要点
- 幂等性
- 每个子事务和补偿操作需支持幂等性,确保重复调用不会产生副作用
- 例如,支付和退款操作需根据订单状态判断是否已执行
- 日志记录
- 记录每个子事务和补偿操作的详细日志,便于排查问题和数据恢复
- 超时机制
- 为每个子事务设置超时时间,超时后自动触发补偿操作
上次更新: 2025/2/19 16:42:39