分布式系统设计的7月回顾:从CAP理论到实际落地的工程权衡经验
CAP理论背得滚瓜烂熟,但一到真实场景还是不知道怎么选。7月系列文章反复讨论同一个话题:理论到工程的距离。这篇文章把本月分布式主题的核心决策逻辑汇聚到一起,配上可以直接用的决策树——下次技术选型会,可以直接对着这个来。
一、分布式系统的核心决策全景
二、CAP理论的实际权衡:四个经典场景
场景1:支付系统
需求:一笔钱不能少,一笔不能多。 决策:CP - 一致性优先 具体方案: ├── 数据库:MySQL + 半同步复制(至少一个从库确认) ├── 事务:Seata AT模式(自动补偿,无需手写回滚逻辑) ├── 分布式锁:Redis Redisson(红锁算法,防脑裂) ├── 消息:RocketMQ 事务消息(半消息机制保证发送一致性) └── 对账:T+1小时异步对账 + 差异自动补偿 关键点:即使服务暂时不可用(P99延迟增加),也不能出现脏数据。场景2:社交Feed流
需求:用户刷新必须很快看到内容,偶尔少一两条可以接受。 决策:AP - 可用性优先 具体方案: ├── 存储:Redis缓存热点Feed + MySQL异步持久化 ├── 推送:消息队列异步扩散(粉丝数>100万用拉模式) ├── 一致性:最终一致,P99延迟目标 < 50ms ├── 降级:Redis挂掉直接读MySQL(降级但不停服) └── 兜底:预生成热门内容缓存,防止空Feed 关键点:用户感知不到短暂的数据不一致,但能感知到页面打不开。场景3:电商库存
需求:不能超卖(一致性),但能快速减库存(可用性)。 决策:混合策略 - 核心操作走CP,展示走AP 具体方案: ├── 扣库存:Redis Lua脚本原子操作(单机Redis,避免分布式) ├── 同步:异步binlog回写MySQL(最终一致) ├── 对账:每15分钟Redis与MySQL对比库存 ├── 防超卖:MySQL做最终兜底校验 └── 展示:允许短时间Redis和MySQL库存数不一致 关键点:下单扣库存走强一致,展示库存走最终一致。分区取舍。场景4:分布式调度
需求:任务必须执行一次且仅一次。 决策:CP - 一致性优先 具体方案: ├── 选主:ZooKeeper临时顺序节点(会话断开自动释放) ├── 分片:一致性Hash分配任务到执行节点 ├── 故障转移:Worker心跳超时 → 自动重新分配任务 ├── 幂等:任务执行前检查状态表(唯一键去重) └── 监控:任务积压 > 阈值告警 关键点:宁可任务延迟执行(可用性降低),也不重复执行。三、分布式锁选型决策树
你的业务场景是? ├── 单机Redis够用(QPS < 10万) │ └── Redis SET NX EX(最简单,大部分场景够用) ├── 需要高可靠(Redis有主从切换风险) │ ├── Redisson红锁(多Redis实例,降低脑裂风险) │ └── ZooKeeper临时节点(CP强一致,代价是性能) ├── 需要可重入 │ └── Redisson RLock(基于Redis Hash + Lua脚本) └── 需要公平锁 └── ZooKeeper顺序节点(Fair Lock天然支持) 分布式锁的三个核心问题: 1. 互斥:同一时刻只有一个客户端持有锁 ✓ 2. 死锁:客户端崩溃后锁自动释放(需设置过期时间)✓ 3. 误删:释放锁时校验锁的持有者(Lua脚本比对value)✓四、分布式消息的可靠性保障
消息可靠性三阶段
| 阶段 | 问题 | 解决方案 | 复杂度 |
|---|---|---|---|
| 生产阶段 | 消息发送失败 | 同步发送+重试 / 事务消息 | 低/中 |
| 存储阶段 | Broker宕机消息丢失 | 多副本同步(min.insync.replicas ≥ 2) | 中 |
| 消费阶段 | 消费失败/重复消费 | 手动提交+幂等消费 | 中 |
消息幂等方案速查
| 方案 | 原理 | 适用场景 | 优缺点 |
|---|---|---|---|
| 数据库唯一键 | INSERT带唯一业务ID | 消费结果需要持久化 | 最简单,依赖DB |
| Redis SETNX | 消费前SETNX标记 | 高频消费场景 | 高性能,需处理Redis不可用 |
| 版本号 | UPDATE带版本号条件 | 数据更新场景 | 不依赖额外存储 |
| 状态机 | 状态流转前检查当前状态 | 有明确状态流转 | 业务侵入性较强 |
分布式事务选型速查
| 方案 | 一致性 | 性能 | 复杂度 | 推荐场景 |
|---|---|---|---|---|
| Seata AT | 最终一致(秒级) | 中 | 低 | 内部微服务间事务 |
| TCC | 最终一致 | 高 | 高 | 需要自定义资源预留 |
| Saga | 最终一致 | 高 | 高 | 长事务、跨系统 |
| 本地消息表 | 最终一致(分钟级) | 高 | 中 | 异步解耦场景 |
| RocketMQ事务消息 | 最终一致(秒级) | 高 | 低 | 消息驱动的事务 |
五、总结
7月分布式系统的文章反复论证了一个核心观点:不存在完美的分布式方案,只存在适合当前约束的方案。关键不是记住CAP理论的定义,而是能迅速判断自己面对的场景属于哪一类,然后准确选择方案。
实战决策口诀:
- 钱相关的(支付/转账/清结算)→ CP,用Seata AT + 半同步复制
- 看的内容(Feed/推荐/搜索)→ AP,用缓存 + 异步 + 最终一致
- 库存类的(电商/票务)→ 混合,扣减走CP,展示走AP
- 协调类的(分布式锁/选主)→ CP,Redis红锁或ZK
8月计划深入讨论分布式系统的混沌测试——如何主动注入故障来验证方案的有效性,而不是等线上出问题才知道哪里不够好。
本文为7月分布式系统设计系列文章的精华汇总。方案选型需结合具体业务场景和团队能力综合判断。
资料说明
本文中的协议、版本、性能、成本和行业趋势应以可核验的一手资料为准。未标注统计口径的比例、时间表和预测仅作工程讨论,不应视为行业事实。可参考 0731 资料来源索引,并在发布前将具体来源贴到对应断言之后。