适用读者:冲架构师岗、要回答"你怎么保证高可用/一致性"的人。
前置:S17(分布式与中间件)、S25-J11(MQ)、J09/J10。
覆盖旧文:3465(分布式面试题,7 域)、3481(分布式锁高可用)、3482(分布式事务)、3485(高可用)、3486(服务隔离)、3471(熔断策略)→ 6 篇 / 约 8 万字符。
扩展点:E-S25-037(高可用的度量与四层手段)、E-S25-038(分布式锁的五个坑与工业级方案)、E-S25-039(分布式事务五方案对比与选型)、E-S25-040(隔离与熔断的边界)。
上一篇:S25-J11 · 消息队列与 Kafka 题库:不丢、不重、不乱序
下一篇:题库层第 7 篇 · 高并发系统设计题(待写)。
1. 一句话结论
高可用不是"多加机器",是"把故障域切小 + 让失败可降级 + 让恢复可验证"。 面试的三段式回答:量化目标(几个 9、MTTR 多长)→ 故障域与手段 → 验证与演练。
出处:
A-3465、A-3485(高可用)、A-3481(分布式锁)、A-3482(分布式事务)、A-3486(隔离)、A-3471(熔断)。
2. 高可用的度量与四层手段(E-S25-037)
| 可用性 | 年停机 | 常见手段 |
|---|---|---|
| 99% | 87.6 h | 单机 + 备份 |
| 99.9% | 8.76 h | 主从 + 自动切换 |
| 99.99% | 52.6 min | 多可用区 + 熔断降级 |
| 99.999% | 5.26 min | 多地域 + 单元化 + 演练 |
四层手段(从便宜到贵):
| 层 | 手段 | 边界 |
|---|---|---|
| 冗余 | 多实例、多副本、多 AZ | 只防"单点",不防"共因故障"(同机架/同版本 bug) |
| 隔离 | 线程池/信号量/集群/机房隔离 | 隔离粒度越细,资源利用率越低 |
| 降级 | 关非核心、返回兜底数据、静态化 | 需预先设计"降级开关"与业务确认 |
| 可观测与演练 | 指标 + 告警 + 混沌演练 | 没演练过的切换 = 没做 |
判据(必答):MTTR 比 MTBF 更重要——真实系统一定会故障,能不能 5 分钟内恢复决定可用性等级。
共因故障清单:同一物理机、同一机架、同一网络出口、同一配置中心推送、同一次全量发版、同一份缓存 key 热点。
3. 分布式锁:五个坑(E-S25-038)
① SETNX lock any_value → 释放时可能删掉别人的锁
② SET lock val NX EX 30 → 原子加锁 + 过期,正确起点
③ value 用唯一标识(UUID) → 释放前比对,Lua 保证原子
④ 业务超时 → 锁过期 → 别人拿到了 → 需 watchdog 续期
⑤ 主从异步复制 → 主挂后从无此锁 → 可能双持锁
| 坑 | 后果 | 解法 |
|---|---|---|
非原子加锁(SETNX + EXPIRE 分两步) |
中间宕机 → 永不过期死锁 | 用 SET ... NX EX 单命令 |
| 无唯一 value | 误删他人锁 | value=UUID,Lua 比对后删 |
| 无续期 | 长任务锁提前释放 | watchdog(Redisson 默认 30 s/10 s 续期) |
| 等待策略粗暴 | 空轮询打爆 Redis | 指数退避 + 最大等待≈锁平均持有时间 |
| 主从切换 | 双客户端同时持锁 | Redlock(有争议)或 ZK/etcd(CP) |
选型判据:
| 场景 | 选择 |
|---|---|
| 高吞吐、可容忍极小概率双持 | Redis(AP) |
| 绝对不能双持(金钱/库存扣减) | etcd/ZK(CP)+ fencing token |
| 单机多线程 | 本地锁(ReentrantLock) |
"fencing token"是加分项:锁服务返回单调递增序号,下游资源校验序号——即使双持锁,旧锁的写也会被拒绝。
4. 分布式事务五方案(E-S25-039)
先分清两类上下文(高频追问):
| 类型 | 场景 | 方案来源 |
|---|---|---|
| 数据库实例间 | 分库分表跨库更新 | ShardingSphere 等中间件(XA/柔性) |
| 跨服务业务层 | 下单→扣库存→支付 | Seata 等协调器 |
| 方案 | 机制 | 一致性 | 性能 | 适用 |
|---|---|---|---|---|
| 2PC/XA | 协调者 prepare/commit | 强一致 | 差(锁资源久、协调者单点) | 短事务、低并发 |
| 3PC | 加 canCommit 阶段 | 减少阻塞 | 更差 | 教学为主 |
| TCC | Try 预留 / Confirm / Cancel | 最终一致(业务侵入大) | 好 | 资金、库存 |
| Saga | 长事务拆本地事务 + 补偿 | 最终一致 | 好 | 长流程、跨多服务 |
| 本地消息表 / 事务消息 | 本地事务 + 消息投递 | 最终一致 | 好 | 异步解耦型业务 |
TCC 的三个坑(必答):
① 空回滚:Try 未执行,Cancel 先到 → 需"防悬挂"(记录 Try 标记)
② 幂等:Confirm/Cancel 可能重复 → 唯一键/状态机
③ 悬挂:Cancel 先执行,Try 后到 → 需按事务 ID 拒绝迟到的 Try
判据:强一致要付性能代价,最终一致要付"补偿逻辑 + 幂等 + 对账"的复杂度。选型先问"业务能否容忍中间态"。
5. 隔离与熔断的边界(E-S25-040)
隔离的六种形态:
| 形态 | 手段 | 代价 |
|---|---|---|
| 机房/地域隔离 | 核心业务独立机房 | 成本最高 |
| 集群隔离 | VIP 与普通用户分集群 | 利用率下降 |
| 服务隔离 | 独立部署 + 独立数据库 | 运维复杂 |
| 线程池隔离 | 每依赖一个线程池 | 线程数膨胀 |
| 信号量隔离 | 计数限并发 | 不支持超时(同步阻塞) |
| 数据隔离 | 分库分表/独立 schema | 跨库查询难 |
一个常见误区(原文强调):核心与核心之间也要隔离——都部署在一台机器上,宕机就一起挂。
熔断的三态与阈值:
CLOSED →(错误率 > 50% 且样本 ≥ 20)→ OPEN →(等待 30 s)→ HALF_OPEN
HALF_OPEN → 试探成功 → CLOSED;失败 → OPEN
阈值设计要点:按错误率 + 最小样本量双条件(防少量请求误熔断);OPEN 期间快速失败 + 走降级;不要对强依赖下游熔断后静默返回空——要有业务兜底(缓存/默认值/人工)。
6. 场景题:一句话答法
| 问题 | 答法 |
|---|---|
| 你的系统怎么保证高可用 | 目标 SLA → 故障域 → 冗余/隔离/降级/演练 → MTTR 指标 |
| 分布式锁怎么保证高性能 | 锁粒度小(分段锁)、等待用退避、锁内不放大事务 |
| 跨服务一致性怎么保证 | 优先本地消息表;资金类 TCC;长流程 Saga + 对账 |
| 熔断会不会误伤 | 双条件阈值 + HALF_OPEN 试探 + 按接口分级 |
7. 反例:五种"听起来高级"的错答
| 说法 | 问题 |
|---|---|
| "用 Redis 分布式锁就万无一失" | 主从切换会双持锁;必须配 fencing/CP 存储 |
| "2PC 是最可靠的,所以我们用它" | 性能与协调者单点问题;高并发不适用 |
| "加了副本就高可用" | 共因故障(同机架/同版本 bug)照样全挂 |
| "熔断就是返回默认值" | 静默兜底会掩盖故障,需告警 + 业务确认 |
| "TCC 就是两阶段提交" | TCC 是业务层预留/确认/取消,与 XA 的资源锁不同 |
8. 自测
- 四个 9 与五个 9 的年停机时间?为什么 MTTR 比 MTBF 重要?
- 分布式锁的五个坑?什么是 fencing token?
- 2PC / TCC / Saga / 本地消息表 的一致性与性能如何取舍?
- TCC 的空回滚、悬挂、幂等分别怎么解?
- 熔断的阈值为什么要"错误率 + 最小样本量"双条件?
答案
- 52.6 min / 5.26 min;系统必然故障,恢复速度决定可用性等级。
- 非原子加锁、无唯一 value、无续期、粗暴等待、主从切换;fencing = 单调序号,下游校验拒绝旧锁写入。
- 2PC 强一致低性能;TCC 最终一致高性能高侵入;Saga 适合长流程;本地消息表适合异步。
- 防悬挂(记录 Try)、唯一键/状态机幂等、按事务 ID 拒绝迟到 Try。
- 防少量请求(如 2 个失败)造成误熔断。
9. 下一篇
题库层第 7 篇 · 高并发系统设计题(约 60 篇旧文)—— 限流器与阈值设定、短链、直播评论、秒杀库存、IM 推送的标准答法与容量估算。
本篇属于系列《S25 · 求职与面试》。旧文来源:A-3465/3471/3481/3482/3485/3486;扩展点 E-S25-037/038/039/040。技术细节以 duplicate_ref 指回 S17 主讲系列。