从单机到分布式:一致性实战(七)总结:演进全景与选型指南

演进全景 让我们回顾小明的二手书平台从诞生到成熟的完整演进路径: 第一阶段:单机时代 └── 问题:并发修改导致数据错乱 └── 方案:数据库事务、隔离级别、乐观锁/悲观锁 第二阶段:读写分离 └── 问题:从库延迟导致读取过期数据 └── 方案:强制读主、时间窗口、会话级路由、同步复制 第三阶段:引入缓存 └── 问题:数据库与缓存数据不一致 └── 方案:Cache-Aside、延迟双删、CDC、LISTEN/NOTIFY 第四阶段:数据分片 └── 问题:跨分片查询和事务 └── 方案:并行查询、全局索引、CQRS、Saga、消息驱动 第五阶段:服务拆分 └── 问题:跨服务操作无法保证原子性 └── 方案:TCC、Saga、本地消息表、AT 模式 第六阶段:消息驱动 └── 问题:消息丢失、重复、乱序 └── 方案:本地消息表、幂等消费、顺序保证、死信队列 每一个阶段都是为了解决上一阶段的瓶颈,但同时也引入了新的一致性挑战。没有银弹,只有权衡。 一致性问题分类 按数据存储分类 类型 问题描述 典型场景 章节 单存储并发 多个请求同时修改同一数据 库存扣减、余额变更 第一章 主从复制延迟 从库数据落后于主库 读写分离架构 第二章 多存储不一致 数据库与缓存数据不同步 缓存架构 第三章 跨分片一致性 分片间数据操作不一致 分库分表架构 第四章 跨服务事务 多服务操作无法原子提交 微服务架构 第五章 消息可靠性 消息丢失/重复/乱序 事件驱动架构 第六章 按一致性强度分类 强一致性 最终一致性 │ │ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ 单机事务 │ │ 同步复制 │ │ TCC │ │ Saga │ │ 消息驱动 │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │ 性能最低 性能较低 性能中等 性能较高 性能最高 解决方案速查表 单机并发问题 方案 原理 优点 缺点 适用场景 数据库事务 ACID 保证 简单可靠 单机限制 单数据库场景 悲观锁 SELECT FOR UPDATE 强一致 阻塞等待 冲突频繁 乐观锁 版本号检查 无阻塞 需要重试 冲突较少 SERIALIZABLE 最高隔离级别 无并发问题 性能差 金融核心 读写分离一致性 方案 原理 延迟容忍 性能影响 适用场景 强制读主 关键操作读主库 零延迟 高 余额查询 时间窗口 写后短时间读主 秒级 中 普通业务 会话级路由 同会话读主 会话内零延迟 中 用户体验敏感 同步复制 等待从库确认 零延迟 高 强一致要求 业务容忍 接受延迟 秒级 无 非关键数据 缓存一致性 方案 原理 一致性强度 实现复杂度 适用场景 Cache-Aside 先更DB再删缓存 最终一致 低 通用场景 延迟双删 二次删除 最终一致(更强) 中 高一致要求 Write-Through 同时写DB和缓存 最终一致 中 缓存托管 Write-Behind 异步批量写DB 弱一致 高 高写入场景 CDC 监听DB变更 最终一致 高 无侵入需求 LISTEN/NOTIFY PG 通知机制 最终一致 低 PostgreSQL 跨服务事务 方案 原理 隔离性 性能 实现复杂度 适用场景 TCC 预留-确认-取消 好 中 高 短事务、金融 Saga 正向+补偿 差 高 中 长事务 本地消息表 事务写消息 差 高 低 异步场景 AT 模式 自动undo log 中 低 高 低侵入需求 消息可靠性 问题 方案 原理 消息丢失 本地消息表 事务保证写入 消息丢失 事务消息 半消息机制 消息重复 幂等消费 去重+业务幂等 消息乱序 单分区 同 key 同分区 消息乱序 序列号检查 消费端校验 消费失败 死信队列 隔离问题消息 跨分片一致性 问题 方案 一致性 性能 跨分片查询 并行查询 强一致 差 跨分片查询 全局索引 最终一致 中 跨分片查询 CQRS 最终一致 好 跨分片事务 2PC 强一致 差 跨分片事务 Saga 最终一致 好 跨分片事务 消息驱动 最终一致 好 选型决策树 总体决策流程 遇到一致性问题 │ ├─ 1. 先问:真的需要强一致吗? │ ├─ 金融、交易、核心业务 → 需要 │ └─ 统计、展示、非核心 → 最终一致即可 │ ├─ 2. 再问:能简化架构吗? │ ├─ 能不拆服务就不拆 │ ├─ 能不分库就不分 │ └─ 能单机解决就单机 │ └─ 3. 最后:选择合适的方案 └─ 见下方详细决策树 详细决策树 ┌─────────────────────────────────────────────────────────────┐ │ 一致性问题决策树 │ └─────────────────────────────────────────────────────────────┘ 问题类型是什么? │ ├─ 单库并发问题 │ ├─ 冲突频率高? → 悲观锁 (SELECT FOR UPDATE) │ ├─ 冲突频率低? → 乐观锁 (版本号) │ └─ 极端要求? → SERIALIZABLE 隔离级别 │ ├─ 读写分离延迟 │ ├─ 能容忍秒级延迟? → 业务容忍 │ ├─ 需要写后即读一致? → 时间窗口读主 │ ├─ 整个会话需要一致? → 会话级路由 │ └─ 绝对不能延迟? → 同步复制(慎用) │ ├─ 缓存不一致 │ ├─ 通用场景? → Cache-Aside │ ├─ 需要更强一致? → 延迟双删 │ ├─ 不能改代码? → CDC │ └─ 用 PostgreSQL? → LISTEN/NOTIFY │ ├─ 跨服务事务 │ ├─ 需要资源隔离? → TCC │ ├─ 是长事务? → Saga │ ├─ 可以异步? → 本地消息表 │ └─ 要低侵入? → AT 模式(如 Seata) │ ├─ 消息可靠性 │ ├─ 担心丢失? → 本地消息表 + At-Least-Once │ ├─ 担心重复? → 幂等消费 │ ├─ 担心乱序? → 单分区 + 序列号 │ └─ 担心堆积? → 死信队列 + 告警 │ └─ 跨分片问题 ├─ 查询问题 │ ├─ 查询少? → 并行查询所有分片 │ ├─ 查询复杂? → CQRS + 查询库 │ └─ 需要实时? → 全局索引 └─ 事务问题 ├─ 能避免跨分片? → 调整分片策略 ├─ 必须强一致? → 2PC(慎用) └─ 可最终一致? → Saga 或消息驱动 常见误区 误区一:追求强一致性 很多时候,最终一致性就够了。强一致性的代价是: ...

December 11, 2025 · 4 min · 646 words · Nanlong

分布式一致性演进史(七):实战篇,方案选型与落地

理论学了一堆,项目里怎么用?这篇我们聊聊真实场景:库存扣减怎么防超卖、分布式锁怎么才安全、跨服务调用怎么保证一致性。 ...

December 8, 2025 · 7 min · 1321 words · Nanlong

分布式一致性演进史(六):现代方案,从 Spanner 到 TiDB

经过几十年的探索,我们终于找到了在全球规模下同时获得强一致性和高可用性的方法。Google Spanner 用原子钟改写了规则,TiDB 用软件方案让它平民化。 ...

December 8, 2025 · 4 min · 668 words · Nanlong

分布式一致性演进史(五):CRDT,无需协调的合并魔法

想象一种数据结构:无论节点之间怎么同步,以什么顺序同步,最终结果都一样。不需要协调,不需要解决冲突。这就是 CRDT 的魔法。 ...

December 8, 2025 · 4 min · 775 words · Nanlong

分布式一致性演进史(四):最终一致性,不强求但终会一致

强一致性很美好,但代价是延迟和可用性。亚马逊的 Dynamo 论文问了一个问题:如果允许短暂不一致,能换来什么?答案是:永远可用。 ...

December 8, 2025 · 3 min · 564 words · Nanlong

分布式一致性演进史(三):Paxos 与 Raft,让多数人达成共识

Paxos 是分布式共识的开山之作,但它难懂到作者自己都承认。Raft 的目标很简单:让工程师能看懂。它成功了。 ...

December 8, 2025 · 4 min · 801 words · Nanlong

分布式一致性演进史(二):2PC 与 CAP,理想的破灭

两阶段提交是分布式事务的第一次认真尝试。它几乎成功了,直到协调者挂掉的那一刻。然后 CAP 定理告诉我们:你不能同时拥有一切。 ...

December 8, 2025 · 3 min · 555 words · Nanlong

分布式一致性演进史(一):单机到分布式,一致性为何变难

在单机世界里,你以为理所当然的事情,到了分布式世界全部失效。网络会断、时钟会漂、节点会挂——欢迎来到真实的分布式世界。 ...

December 8, 2025 · 3 min · 490 words · Nanlong

架构演进史(七):微服务与云原生,分布式的代价

「我们拆成了 50 个微服务!」CTO 自豪地说。半年后,我们花了 60% 的时间处理服务间通信、分布式事务和部署问题。代码量没减少,复杂度却指数级增长。 ...

December 8, 2025 · 5 min · 982 words · Nanlong