

















分布式事务不是怎么选的问题,首先就是能不用就不用 实在要用那就是 一致性等级划分问题
你必须先问:
单库事务(ACID) 2PC(Two-Phase Commit,两阶段提交)TCC(Try-Confirm-Cancel,尝试确认取消)
|
100 |
可以 2PC |
|
1000 |
TCC 或 本地事务 |
|
10000+ |
必须异步最终一致 |
高并发 + 强一致 = 性能灾难。
假设:
100 QPS × 单次事务耗时 = 并发事务数
第一步:估算单次事务耗时
假设:
第二步:计算并发事务数 公式: 并发数 ≈ QPS × 事务耗时(秒) 并发数 = 100 × 0.05 = 5个并发
mysql 的并发 可以调整到 1000+ 但是这只是并发请求 实际上的qps 是并发事务的响应时间
数据库并发通常有三层含义:
真正危险的不是高 QPS。 而是:长事务 × 热点数据
微服务并不一定需要分布式事务,关键取决于是否存在跨服务的强一致写操作。
在架构设计中,我会先做一致性等级划分:
而不是默认所有微服务都使用分布式事务。
单机事务 → ACID
分布式系统 → CAP 约束
工程妥协 → BASE 思想
具体实现 → 2PC / TCC / Outbox / Saga
|
字母 |
含义 |
核心关注点 |
|
A Atomicity |
原子性 |
要么全成要么全失败 |
|
C Consistency |
一致性 |
不违反业务规则 |
|
I Isolation |
隔离性 |
并发不干扰 |
|
D Durability |
持久性 |
提交后不丢 |
|
维度 |
2PC |
TCC |
Outbox Pattern |
Saga |
|
一致性模型 |
强一致(CP) |
强一致(可控) |
最终一致(BASE) |
最终一致(BASE) |
|
本质机制 |
数据库层两阶段提交 |
业务层预留资源 |
本地事务+可靠消息 |
本地事务+补偿事务 |
|
是否阻塞 |
是 |
否(数据库层) |
否 |
否 |
|
是否需要补偿 |
否 |
是(Cancel) |
重试机制 |
必须有补偿 |
|
锁持有时间 |
长 |
短 |
本地事务时间 |
本地事务时间 |
|
对业务侵入 |
低 |
高 |
低 |
中等 |
|
性能 |
低 |
中 |
高 |
高 |
|
可扩展性 |
差 |
中 |
好 |
好 |
|
实现复杂度 |
中 |
高 |
低 |
中高 |
|
适合高QPS |
不适合 |
可支持 |
非常适合 |
适合 |
|
资金核心 |
小规模可用 |
推荐 |
不推荐 |
不推荐 |
|
是否中心协调 |
有(Coordinator) |
无中心锁 |
无 |
取决于编排方式 |
|
常见框架 |
XA / Atomikos |
Seata TCC |
自研+MQ |
Axon / Seata Saga |
一、2PC(Two-Phase Commit) ✅ 优点 理论简单 强一致 数据库原生支持(XA 协议(分布式事务协议)) ❌ 缺点 阻塞严重 协调者单点 扩展性差 长事务风险高 🎯 适用场景 低 QPS 系统 内部系统 节点数量少 对一致性要求极高 🚫 不适用 高并发 互联网核心交易 微服务大规模拆分 二、TCC(Try-Confirm-Cancel) ✅ 优点 强一致 不依赖数据库全局锁 支持高并发 扩展性优于 2PC ❌ 缺点 侵入业务逻辑 开发复杂 必须保证幂等(Idempotent,幂等性) Cancel 设计困难 🎯 适用场景 资金扣减 账户余额变更 库存冻结 支付系统 🚫 不适用 简单 CRUD 低价值系统 三、Outbox Pattern ✅ 优点 简单 性能好 无全局锁 不影响数据库并发能力 ❌ 缺点 最终一致 需要重试机制 需要消息幂等 🎯 适用场景 订单创建后发积分 用户注册后发通知 数据同步 统计系统 🚫 不适用 实时资金强一致 必须秒级对账一致的场景 四、Saga ✅ 优点 适合长事务 不阻塞 易扩展 ❌ 缺点 补偿逻辑复杂 数据可能短时间不一致 业务侵入明显 🎯 适用场景 电商完整下单流程 跨多个微服务 需要事务编排 🚫 不适用 实时账务系统 高精度金融核心
四、为什么必须二选一? 假设场景: 两个节点: Node A Node B 账户余额 = 100 突然网络断开(分区发生) A 和 B 无法通信。 此时发生写请求: 用户在 Node A 扣减 30。 A 变成 70。 现在问题来了: 用户去 Node B 查询余额。 你有两个选择: 选择 1:保证强一致 Node B 不能确认 A 是否已更新。 为了保证一致: 👉 B 必须拒绝请求或等待网络恢复。 结果: 查询失败 服务不可用 你保住了一致性 但牺牲了可用性 这是 CP。 选择 2:保证可用性 Node B 直接返回当前值 100。 结果: 用户看到旧数据 数据不一致 但系统可用。 这是 AP。 五、这就是为什么必须二选一 因为: 分区发生时,节点之间无法同步。 你无法同时做到: 所有节点数据一致 所有节点都响应请求 这是一个数学证明结论。 不是工程选择问题。
拿销账举例 销账更新金额的时候 读不进行租塞,写的时候进行判断 所以可以在表中增加版本号,因为销账有流程为了保证更安全还可以加上状态机 就是待处理只可以变成处理中
ef虽然实现了乐观锁 只需要加上特性就好 但是性能有问题 因为1000条他就会生产1000个update语句
在 .NET 中如果使用 TransactionScope 并跨多个数据库连接,可能会触发 MSDTC,而 MSDTC 底层可能会使用数据库的 XA 实现两阶段提交。
|
方案 |
本质类型 |
控制层级 |
|
2PC(XA) |
数据库层分布式事务 |
资源管理器 |
|
TCC |
业务层两阶段提交 |
应用层 |
|
Outbox |
本地事务 + 可靠消息 |
架构层 |
一句话总结:
典型场景:
阶段 1:Prepare
协调者询问所有参与者是否可以提交
阶段 2:Commit / Rollback
互联网系统几乎不用。
在高并发环境下,如何保证强一致,同时避免数据库长锁?
Try:预留资源 (冻结金额)
Confirm:正式提交(扣减金额)
Cancel:回滚补偿(解冻金额)
本质:业务层 2PC
财务系统“钱”的场景。
核心:
本地事务写:
异步发送。
财务系统“单据流转”的场景。
|
对比维度 |
2PC |
TCC |
Outbox |
|
一致性 |
强一致 |
强一致 |
最终一致 |
|
锁资源 |
数据库锁 |
业务冻结 |
无锁 |
|
并发能力 |
低 |
中 |
高 |
|
侵入性 |
低 |
高 |
低 |
|
实现复杂度 |
低 |
高 |
中 |
|
是否阻塞 |
是 |
部分 |
否 |
|
是否适合互联网 |
不适合 |
部分场景 |
非常适合 |
|
场景 |
推荐方案 |
|
账户余额扣减 |
TCC |
|
销账单生成 |
Outbox |
|
订单状态流转 |
Outbox |
|
跨库强一致账务 |
2PC(极少) |
你可以这样回答:
2PC 是数据库层分布式事务方案,保证强一致,但性能较低,适用于并发不高的金融核心系统。
TCC 是业务层两阶段提交,通过冻结资源实现强一致,适合资金类场景,但侵入性较高。
Outbox 是通过本地事务写消息表,再异步发送消息实现最终一致,是互联网系统主流方案,适合高并发业务场景。
在实际架构中,应根据一致性等级分级设计,而不是一刀切。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。