本章要回答的三个问题:Redis 靠什么把读写做到亚毫秒级,又靠什么在内存易失的前提下保住数据(数据类型、持久化)?生产环境最危险的缓存三大故障(穿透、击穿、雪崩)怎么防?从单机到哨兵再到集群,它的可用性与扩展能力分别走到哪一步、边界在哪?
2.1 节画过键值门派的地图,但 Redis 值得再花八章里的八章来深访——它在生产环境的使用密度太高,高到几乎每个后端服务的可用性都间接系在它身上。也正因为如此,Redis 的"会用"与"用好"之间隔着大量生产事故:缓存雪崩打垮数据库、误删数据无法恢复、哨兵切换丢失写入、集群模式下一个 Lua 脚本跑不了。这一章的目标就是把这些坑在字面上先踩一遍,让你在真实的坑面前认得出它们。
与第 4 章的对照关系是本章的阅读线索:MongoDB 的复制集与 Redis 哨兵面对同样的主从切换问题,答案却因一致性哲学不同而不同;MongoDB 的分片与 Redis 集群同样解决扩展,一个靠区间元数据、一个靠固定槽位。第 3 章的内功在两种实现间来回印证,是检验你是否真懂的最佳练习。
读完本章你应当能够:按场景选择正确的数据类型并说出各自的底层结构;为持久化(RDB、AOF、混合)做出与业务丢数据容忍度匹配的配置;设计一套带穿透、击穿、雪崩完整防御的缓存层;用 Lua 脚本实现原子的多步操作(如秒杀扣库存);理解哨兵的判定流程与集群的槽位模型,知道各自的能力边界与替代方案。
| 节号 | 回答哪个问题 | 关键产出 |
|---|---|---|
| 5.1 | Redis 凭什么这么快 | 单线程模型 + 内存 + IO 多路复用 |
| 5.2 | 数据怎么组织 | 五大类型与底层编码 |
| 5.3 | 内存里的数据怎么保命 | RDB 与 AOF 的取舍 |
| 5.4 | 缓存怎么用不出事故 | 三大故障防御 + 淘汰策略 |
| 5.5 | 消息怎么传 | Pub/Sub 与 Streams |
| 5.6 | 多步操作怎么原子 | 事务与 Lua 脚本 |
| 5.7 | 主库挂了怎么办 | 哨兵判定与切换 |
| 5.8 | 容量怎么扩 | 槽位集群与限制 |
前四节是"单机生存线"(快、存、保、防),后四节是"分布式延伸线"(消息、原子、可用、扩展)。每节末尾的取舍讨论都刻意与第 4 章 MongoDB 的对应机制互相呼应。
需要第 2.1 节的键值模型概念、第 3 章的复制与一致性档位。示例全部使用 redis-cli 交互环境,命令即学即用。
读本章时不断与 MongoDB 对照,是理解两套设计哲学最快的方式。
| 主题 | Redis 的做法 | MongoDB 的做法 | 差异根源 |
|---|---|---|---|
| 数据主存 | 内存为主,持久化是补救 | 磁盘为主,内存做缓存 | 目标负载不同:低延迟 vs 大容量 |
| 复制 | 异步追赶,默认可能丢 | 多数派确认可选,偏不丢 | 可用性优先 vs 一致性优先 |
| 故障切换 | 哨兵投票判定 | 复制集内部选举 | 外部组件 vs 内建机制 |
| 扩展 | 固定 16384 槽位哈希 | 按分片键区间的 chunk | 分布均匀 vs 范围查询友好 |
| 原子性 | 单线程 + Lua 脚本 | 多文档事务 | 靠执行模型 vs 靠事务机制 |
| 查询能力 | 只有键访问 | 丰富的查询与索引 | 极简 vs 通用 |
前四节是"单机生存线":5.1 弄清它为什么快、5.2 会用五种类型、5.3 保证数据不丢、5.4 保证缓存不出事故。这四节覆盖了日常开发的绝大多数场景,也是面试与排错的高频区。
后四节是"分布式延伸线":5.5 消息传递、5.6 原子操作、5.7 高可用、5.8 水平扩展。这四节决定 Redis 能否从"一个缓存"成长为"系统里的关键组件"。
贯穿全章的一条暗线是"丢失窗口":异步复制会丢、AOF 每秒刷盘会丢、哨兵切换会丢、缓存过期会丢。Redis 的高性能很大程度上来自对这些窗口的容忍。因此使用 Redis 的第一准则始终是——先问这份数据丢得起吗。丢得起,Redis 是你的最佳搭档;丢不起,让它当缓存,别让它当账本。
本章结束后,五大门派的两个代表(文档、键值)都已深访完毕,全册的巡礼也随之收官。2.5 节的新兴门派地图 + 第 3 章的通用内功 + 两个深访样本,合起来就是你在实际项目里做存储选型与排错的完整工具箱。