Java面试要点:分布式锁、事务一致性与最终一致性
前言
分布式一致性是企业系统里最容易被问深的一类题目。面试常见问题包括:
- 分布式锁为什么不是银弹。
- 本地事务和 MQ 怎么保持一致。
- 最终一致性怎么理解。
- TCC、Saga、补偿事务有什么区别。
- 什么时候可以不用分布式锁。
为什么会有一致性问题
在单体应用里,数据库事务能把很多事情一次性包住。
但到了分布式系统里:
- 下单服务和库存服务不在一个进程。
- 支付系统和订单系统不在一个事务里。
- MQ、Redis、数据库、第三方接口各自独立。
所以必须在“强一致、可用性、性能、复杂度”之间做取舍。
flowchart TD
A[一个业务动作] --> B[数据库]
A --> C[Redis]
A --> D[MQ]
A --> E[第三方接口]
B --> F[原子性边界]
C --> G[缓存一致性]
D --> H[消息最终一致]
E --> I[外部系统不确定性]
分布式锁什么时候用
适合:
- 定时任务抢占。
- 短临界区互斥。
- 防重复执行。
- 分布式资源竞争。
不适合:
- 复杂长事务。
- 需要跨多个系统强原子完成的流程。
- 依赖多个阶段补偿的业务。
方案一:Redis 分布式锁
优点:
- 快。
- 简单。
缺点:
- TTL、续期、主从切换问题。
- 只能保证互斥,不保证整体业务一致。
方案二:ZooKeeper/etcd 锁
优点:
- 一致性协调能力更强。
缺点:
- 成本更高。
方案三:数据库锁或唯一约束
优点:
- 和业务数据绑定。
缺点:
- 并发能力弱于缓存类方案。
| 方案 | 优点 | 缺点 | 场景 |
|---|---|---|---|
| Redis 锁 | 快、轻量 | 失效和一致性问题 | 短临界区 |
| ZooKeeper/etcd | 强协调 | 成本高 | 选主、调度 |
| 数据库锁 | 贴近数据 | 性能弱 | 强约束更新 |
本地事务和消息一致性
这是企业里最经典的一致性题。
场景:
- 订单服务写本地数据库。
- 同时发一条消息通知库存、营销、积分系统。
- 如果消息发成功但数据库回滚,就会脏。
- 如果数据库成功但消息没发出去,就会漏。
常见方案:
方案一:事务消息
先写半消息,再执行本地事务,成功后提交。
优点:
- 较自然地解决本地事务和消息一致性。
缺点:
- 平台依赖强。
方案二:本地消息表
先写业务数据和本地消息表,再异步投递消息。
优点:
- 通用。
- 可补偿。
缺点:
- 需要后台投递任务。
方案三:Outbox 模式
业务表和事件表放在一起,靠增量同步发布事件。
优点:
- 工程上稳定。
缺点:
- 需要额外同步机制。
sequenceDiagram
participant S as 业务服务
participant D as 数据库
participant M as MQ
S->>D: 写业务记录
S->>D: 写 outbox 事件
D-->>M: 同步发布事件
M->>下游: 消费事件
最终一致性怎么理解
最终一致性不是“永远不一致”,而是:
- 允许短暂不一致。
- 通过重试、补偿、对账,最终收敛到一致。
典型场景:
- 支付成功后订单状态稍后更新。
- 库存预占后异步确认。
- 发券失败后补偿。
面试可以这样说:
企业里很多分布式流程做不到强一致,就用最终一致性。核心是有补偿、有对账、有幂等,而不是只靠一次成功。
TCC、Saga、补偿事务
TCC
Try、Confirm、Cancel。
适合:
- 金融、库存、强控制场景。
缺点:
- 开发成本高。
Saga
把长事务拆成多个本地事务,每步失败就执行补偿动作。
适合:
- 长链路业务。
缺点:
- 补偿逻辑复杂。
补偿事务
以业务补偿为主,不追求强原子。
适合:
- 订单、物流、售后。
对比:
| 方案 | 优点 | 缺点 |
|---|---|---|
| TCC | 控制强 | 实现复杂 |
| Saga | 适合长链路 | 补偿难 |
| 补偿事务 | 工程实用 | 业务语义要设计好 |
幂等为什么是基础能力
无论是锁、MQ、事务消息还是补偿,最后都离不开幂等。
常见幂等手段:
- 业务唯一键。
- 状态机条件更新。
- 去重表。
- Redis 去重。
- 数据库唯一约束。
1 | update pay_order |
对账和补偿
企业系统里真正的兜底通常靠:
- 定时对账。
- 差异补偿。
- 失败重跑。
- 人工处理。
举例:
- 支付对账发现成功但订单未支付,补写订单状态。
- 库存对账发现预占未释放,做释放补偿。
- MQ 积压时按批次修复。
高频面试题
分布式锁为什么不是银弹?
因为它只能解决互斥,不能天然保证跨系统一致。长链路业务还需要幂等、补偿、对账和最终一致设计。
本地事务和消息怎么保证一致?
常见方案是事务消息、本地消息表或 Outbox 模式。
最终一致性怎么落地?
通过异步消息、重试、补偿、对账和状态机收敛最终状态。
TCC 和 Saga 怎么选?
TCC 控制更强但复杂;Saga 更适合长链路;业务简单时补偿事务往往更实用。
为什么分布式系统一定要做幂等?
因为网络超时、重试、重复消息、重复回调、重复任务都很常见。
总结
分布式一致性回答可以围绕五条主线:
- 分布式锁只解决互斥,不解决全部一致性。
- 消息一致性靠事务消息、本地消息表、Outbox。
- 最终一致性靠重试、补偿、对账。
- TCC、Saga、补偿事务各有边界。
- 幂等是所有分布式方案的底座。
企业里真正可靠的分布式设计,通常不是“一个大事务”,而是“拆分、异步、补偿、收敛”。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Junly博客!
评论


