课程最后一章回答一个被问烂但永远真问题:「项目该用什么数据库?」。我的答案先行:默认 MySQL 或 PostgreSQL + Redis 缓存,有确凿的反对理由才换。这个答案背后是九年互联网项目的集体试错,而要讲清楚它,得把前面九章的零件全部调出来对账:事务(第 7 章)、日志(第 8 章)、索引(第 9 章)、范式与反范式(第 5 章)。选型从来不是「哪个数据库好」,是「你的业务愿意放弃前面哪一章的哪个承诺」。
| 类型 | 代表 | 数据模型 | 强项 | 放弃了什么 |
|---|---|---|---|---|
| 关系型 | MySQL、PG | 表 + 外键 | ACID、连接、复杂查询 | 水平扩展难(单机写) |
| KV 内存型 | Redis | 键 → 值 | 微秒级延迟 | 大数据量、强持久 |
| 文档型 | MongoDB | JSON 文档 | 模式灵活、天然分片 | 连接、跨文档事务(弱) |
| 列式/OLAP | ClickHouse、HBase | 列族 | 聚合分析吞吐 | 单行更新、事务 |
看「放弃了什么」这一列,比看「强项」更有信息量。关系模型是「完全体」:约束、连接、事务、日志、优化器,一应俱全,代价是单机写扩展难(分库分表是杀敌一千自损八百的手艺);每类 NoSQL 都是拿着关系模型的某一块去换专项性能。所以选型的第一步永远是回答:我的核心数据,哪些承诺丢不起? 账务的 ACID 丢不起,购物车的毫秒延迟丢不起,浏览计数连准确都无所谓。
两家都是第 7、8 章原理的完全体实现,差异在细节和气质:
选择建议朴素到土:团队熟谁、招人容易、周边工具链齐,就用谁。两家在正确性上都是值得托付的,差异远小于「用没用对索引、有没有管好长事务」这类第 9 章问题带来的差距。真要一条硬标准:重度复杂分析查询、需要 JSON 字段做半结构化存储的,PG 顺手;超大并发简单读写、生态内分库分表方案成熟的,MySQL 顺手。
Redis 把数据放内存,单个操作微秒级,还附赠一堆精心设计的数据结构,每个都对应一类真实业务:ZSet(跳表实现)做排行榜,INCR 做计数器和限流,Hash 做会话,List 做简单队列,EXPIRE 做验证码过期。它是「加在主库前面的缓存层」的标准答案,经典姿势是 Cache-Aside:
读:先查 Redis,命中直接回;未命中查 MySQL,回写 Redis(带过期时间)
写:先写 MySQL,再删 Redis(下次读时自动回填)
两个必须知道的坑。缓存与库的一致性:写库后删缓存存在时间窗,极端并发下旧值可能回填,资金类数据别依赖缓存,Redis 只放「读得起一次回源」的数据。持久化的诚实边界:RDB 快照 + AOF 追加日志(第 8 章 WAL 的思想)让 Redis 能在重启后恢复大部分数据,但默认配置下「最近一秒」可能丢;缓存丢一秒无所谓,当主存储用就要 appendfsync always(性能大跌),多数人走到这里会重新考虑该不该把 Redis 当主库。
MongoDB 存 JSON 文档,同一集合的文档结构可以各不相同,嵌套对象直接存进去。这对「结构多变、以聚合读为主」的业务(内容管理、埋点事件、商品详情的动态属性)是真正的生产力:免建表、免迁移、一次读出整个文档,不用四表连接拼装。代价回到第 5 章的话题:没有连接,跨文档的关联查询要自己在应用层拼,或者在文档里冗余(反规范化成为默认姿态);跨文档事务有,但那是近年补的课,代价高、生态习惯不围绕它转。经验法则:你的数据天然是「一份独立的文档」(一个商品、一条日志、一封简历),MongoDB 顺手;你的数据天然是「一张关系网」(订单、库存、用户互相牵连),老老实实关系库。
把判断流程写成树,每条分支挂上前文的章节依据:
核心数据有强一致 + 复杂连接需求?
├─ 是 → 关系库(MySQL/PG) [第 2、7、8 章]
│ ├─ 读压力大? → 前面加 Redis 缓存 [Cache-Aside]
│ └─ 单机写到顶? → 先读写分离,再谈分库分表
└─ 否 → 继续问
├─ 追求微秒延迟、结构简单 → Redis(或当缓存) [第 9 章哈希]
├─ 结构多变、免连接的文档 → MongoDB [第 5 章反规范化]
└─ 海量分析聚合、写多读少 → OLAP/列式
最后一条比任何选型表都重要的经验:别让选型焦虑代替索引优化。我见过太多次争论「MySQL 还是 MongoDB」的会议,最后发现瓶颈是那条全表扫描的 SQL(第 9 章)和没人管的长事务(第 7 章)。数据库的坑九成在用法,一成在选型,而选型的九成,「关系库 + Redis」都能罩住。
INCR 实现一个接口限流器(键 rate:{user}:{minute},EXPIRE 60 秒),用 curl 压一下,想想它是怎么做到天然原子的。