本页目录
分布式事务
跨多个服务的一次写操作——没有全局 ACID。2PC 追求强一致但 coordinator 故障时参与者全部阻塞;Saga 和 TCC 用补偿事务换可用性,代价是应用层要自己写回滚逻辑。outbox pattern 和幂等性保证了"至少一次"在工程上的可行性。
单机数据库中事务是 ACID 的——BEGIN/COMMIT/ROLLBACK 即可。分布式系统涉及多个服务的写操作,没有全局的 ACID 事务。
2PC (Two-Phase Commit)
最基础的分布式事务协议——阻塞式,无协调器故障容错。
问题:coordinator crash 在 PREPARE 之后、COMMIT 之前 → participant 处于 uncertain state——它不能单方面 commit(不知道其他 participant 是否 YES),也不能单方面 abort(其他可能已经 commit 了)。参与者阻塞直到 coordinator 恢复——这就是"blocking protocol"。
实践中:XA 事务(2PC 的实现)被用在数据库跨分片事务中,但处理 coordinator crash 需要管理员手动 heuristic commit/abort。
Saga
将长事务拆为多个本地事务 steps,每步有自己的补偿操作(compensating action)。某步失败时,以相反顺序执行已完成的 steps 的补偿。
Saga 没有隔离性(其他事务可以看到中间态),但它不阻塞——任何时刻系统都在 progressing。
编排模式
- Choreography: 每个 service 消费上一个 step 的 event,发布自己完成/失败 event — 无中心编排器
- Orchestration: 中心 Saga 协调器告诉各 service "执行 step" 或 "执行补偿" — 逻辑集中,容易管理
TCC (Try-Confirm-Cancel)
Saga 的变体,适用更"刚性"的资源预留:
Try: 预留资源 (检查库存、冻结余额) — 资源**未消耗**,只是标记为 "待使用"
Confirm: 实际消耗资源 (扣库存、扣款)
Cancel: 释放预留 (释放库存、解冻余额)
与 Saga 的区别:Saga 的 step 直接修改了数据(book_flight 真的订了票),补偿是 undo。TCC 的 Try 只预留,Confirm 才是真正修改——任何时刻都可以 Cancel 而不需要在后续执行 undo。
幂等性
分布式系统中最重要的非功能性要求:f(x) = f(f(x))——重试操作不影响结果。
实现方式:
1. unique idempotency key: client 生成 UUID, server 存储 (key) → (已处理/未处理)
→ 重复 key → 返回缓存的结果, 不重新执行
2. database constraints: INSERT INTO orders VALUES (order_id=123, ...)
→ 重试 → UNIQUE constraint violation → 忽略 or read existing
3. token-based: server 给 client token, client 用 token 标记请求
→ 重复 token → 拒绝
不幂等的例子:
UPDATE users SET balance = balance + 100 -- 重试 = 加了 2 次!
改法: UPDATE users SET balance = ? WHERE version = ? (optimistic lock)
Outbox Pattern
事务性写数据库 + 发消息给消息队列——如何保证两者原子?不能先写 DB 再发消息(DB 写成功但消息发送失败 → inconsistent)。
[本地事务]:
INSERT INTO orders (...);
INSERT INTO outbox (event_type, payload, created_at) VALUES ('order_created', '...', NOW());
COMMIT; ← 两者在同一个本地事务中!
[Outbox Poller]:
SELECT * FROM outbox ORDER BY id → 发到 Kafka/MQ → 成功 → 删除 from outbox
保证:order 写入 + event 产生是原子的(same transaction)。Outbox poller 做 at-least-once delivery。
参考
- 论文: "Sagas" (Garcia-Molina & Salem, 1987)
- 微服务事务: microservices.io/patterns/data/saga.html
- 幂等: stripe.com/docs/idempotency (生产级实现)
Keywords: 2PC, XA, Saga, TCC, compensating action, idempotency, outbox pattern, distributed transaction