数据层:SQL vs NoSQL 与复制
「SQL 还是 NoSQL」是面试深挖环节的必考题,也是工作中最常见的架构分歧。答对的关键不是站队,而是说清决策依据——这恰好也是你在设计评审中说服团队的方式。本课依据 DDIA 复制章节[1]。
§1 · 决策框架五个问题定生死
不要问「哪个数据库更好」,问这五个问题:
| 问题 | 指向 SQL | 指向 NoSQL |
|---|---|---|
| ① 数据结构? | 结构化、关系多(订单-商品-用户) | 松散、嵌套文档、超简单 KV |
| ② 事务需求? | 强 ACID(钱、库存) | 可容忍最终一致(点赞数) |
| ③ 查询模式? | 任意条件组合、JOIN、聚合 | 按主键/固定模式读写 |
| ④ 规模? | 单机/少量读写分离可扛 | 海量写入、数据量单机装不下 |
| ⑤ 演进速度? | Schema 稳定 | 字段频繁变化、异构数据 |
NoSQL 四大家族快速定位:KV(Redis/DynamoDB——按 key 读写,快);文档(MongoDB——JSON 式嵌套对象);宽列(Cassandra——海量写入、按分区键查询);图(Neo4j——关系即数据,社交/风控)。
「数据量大所以用 NoSQL」是错误推理。正确推理是:查询模式 + 事务需求决定类型,规模决定部署形态。很多「大」系统(包括 Amazon 早期)单机 PostgreSQL 就能跑很久——先读写分离,再谈换库。
§2 · 复制一份数据,多台机器
复制的两个动机:读扩展(读分摊到多副本)和高可用(主库挂了从库顶上)[1]。主流拓扑三种:
| 拓扑 | 机制 | 代价 |
|---|---|---|
| 主从 Leader-Follower | 写全走主库,主库把变更日志同步给从库;读可走从库 | 复制延迟 replication lag:从库读到旧数据 |
| 多主 Multi-Leader | 多个数据中心各有一个主库,互相同步 | 同一数据两地同时改 → 写冲突需要解决 |
| 无主 Leaderless | 读写打到任意副本,靠多数派仲裁(quorum)判断新旧 | 一致性更弱,冲突协调交给客户端/系统 |
复制延迟是面试深挖金矿
经典场景:用户改完个人资料刷新页面,头像没变——写主库成功,读请求却被分到还没同步的从库。这叫读己之写(read-your-writes)被破坏。标准解法:
- 关键读走主库:改完资料后的那次读强制回主库;
- 会话级粘连:同一用户短期内固定读主库(记录最后写入时间戳,从库落后就回退主库);
- 单调读(monotonic reads):同一用户固定粘一个从库,避免「越刷越旧」的时空错乱。
选主(leader election):提升一个从库为新主。坑在「脑裂」(split brain)——旧主没死透,出现双主双写。工业界的答案是一致性算法(Raft)做选主,这是 Lesson 0009 的伏笔,可以先玩一下 Raft 可视化[2]。
§3 · 把它接回四步框架
第 ③ 步画数据层时,用这套话术出口:「本场景读写比 X:Y、需要/不需要跨表事务、预计数据量 Z,因此选 __;读压力先上 N 个只读副本,写扩展留到数据量达 __ 时再分片(Lesson 0006)。」——每句话都有依据,评审官直接通过。
§4 · 随堂检测
§5 · 检索练习
凭记忆回答:① 选库五问是哪五问?② 复制延迟导致什么用户可见的 bug?至少说两个解法。③ 三种复制拓扑各自的代价?
核对参考答案
① 数据结构 / 事务需求 / 查询模式 / 规模 / 演进速度。② 读己之写被破坏(改完刷新看不到)——解法:关键读走主库、会话粘连(时间戳回退)、单调读。③ 主从:复制延迟;多主:写冲突协调;无主:一致性最弱、靠 quorum。
§6 · 本周行动
① 查你公司主库的复制拓扑:几个从库?延迟监控在哪里看?
② 找一处读己之写风险点:修改类操作成功后紧跟的读取,走的是主库还是从库?
③ 用五问法评估:如果明天 DAU 翻 10 倍,你们的库第一个爆掉的是什么?
§7 · 延伸资源
- 首选精读:DDIA「Replication」章(第 1 版第 5 章)——本课的理论母体,值得逐页读[1]
- System Design Primer 的 SQL vs NoSQL 与数据库扩展小节[3]
- Raft 官网可视化:亲手让节点宕机,观察选主[2]
- 下一课 → Lesson 0005 缓存:策略与三大问题