Redis 从零到精通验收清单
这页用来回答:Redis 文档是不是只讲了几个命令和八股题,还是能让零基础真正学会生产级 Redis?
学完 Redis 不能只会说“Redis 快、缓存穿透、分布式锁”。你要能解释 Redis 为什么快、为什么也会慢、命令执行全过程、数据结构适合什么场景、缓存和数据库为什么会不一致、哨兵和集群有什么区别、大 Key 和热 Key 为什么危险、线上 timeout 怎么按证据排查。
最终目标
学完 Redis 专栏后,你至少要能做到:
- 判断一个业务场景是否适合放 Redis。
- 根据访问模式选择 String、Hash、List、Set、ZSet、Bitmap、HyperLogLog。
- 解释 Redis 命令从网络事件到数据结构操作的全过程。
- 解释 Redis 为什么快,以及大 Key、热 Key、慢命令为什么会让它慢。
- 设计 Cache Aside,并处理穿透、击穿、雪崩和缓存一致性。
- 解释 TTL、惰性删除、定期删除、内存淘汰策略。
- 解释 RDB、AOF、主从复制、哨兵、Cluster 的原理和边界。
- 正确使用分布式锁,并知道 Redlock、Fencing Token 的适用边界。
- 排查 timeout、连接池耗尽、慢命令、大 Key、热 Key、主从延迟、Cluster 热点。
- 面试时能标准回答,追问时能跳回原理页讲流程和 Demo。
总路线
flowchart TD
A["阶段 1<br/>场景和数据结构"] --> B["阶段 2<br/>命令执行原理"]
B --> C["阶段 3<br/>缓存模式和一致性"]
C --> D["阶段 4<br/>过期删除和内存淘汰"]
D --> E["阶段 5<br/>持久化和高可用"]
E --> F["阶段 6<br/>高并发缓存问题"]
F --> G["阶段 7<br/>分布式锁"]
G --> H["阶段 8<br/>生产排查"]
H --> I["阶段 9<br/>面试和商业落地"]为什么要按这个顺序?
| 阶段 | 原因 | 如果跳过 |
|---|---|---|
| 先学场景 | Redis 不是 MySQL 替代品 | 核心事实数据误放 Redis |
| 再学数据结构 | 结构决定命令复杂度和内存 | 形成大 Key、慢命令 |
| 再学执行原理 | 知道单线程为什么快也为什么会被阻塞 | 只会背“内存快” |
| 再学缓存一致性 | Redis 最常见用途是缓存 | 旧数据、击穿、雪崩无法处理 |
| 再学过期淘汰 | 缓存一定要面对内存和 TTL | 内存满、Key 不过期看不懂 |
| 再学高可用 | 生产不能只部署单机 | 主从、哨兵、Cluster 混淆 |
| 再学锁 | 分布式锁容易误删和超时失效 | 并发任务重复执行 |
| 最后排查 | 生产问题是多机制叠加 | timeout 只会重启 |
阶段 1:场景和数据结构
Redis 适合保存高频访问、低延迟、临时性或可重建的数据。它通常不是权威事实源。
flowchart TD
A["业务数据"] --> B{"是否强一致且不可丢"}
B -- "是" --> C["优先 MySQL / 关系库"]
B -- "否" --> D{"是否高频访问或临时状态"}
D -- "是" --> E["适合 Redis"]
D -- "否" --> F["不一定需要 Redis"]数据结构验收
| 数据结构 | 适合场景 | 不适合误用 |
|---|---|---|
| String | 缓存、计数器、锁 token | 超大 JSON 对象 |
| Hash | 对象字段、购物车 | field 数无限增长的大 Hash |
| List | 简单队列、时间线 | 可靠消息队列主力 |
| Set | 去重、标签、共同好友 | 需要排序的排行榜 |
| ZSet | 排行榜、延迟任务、TopN | 超大集合全量读取 |
| Bitmap | 签到、是否存在、布尔统计 | 稀疏且 ID 巨大的场景 |
| HyperLogLog | UV 估算 | 需要精确去重明细 |
Demo:资产详情缓存
set asset:detail:1001 '{"id":1001,"name":"CT-001","status":"USED"}' ex 1800
get asset:detail:1001
ttl asset:detail:1001为什么要设置 TTL?
- 防止旧缓存永久存在。
- 释放长期不用的数据。
- 给缓存和数据库不一致提供兜底恢复。
如果是资产字段列表,不要把全医院所有字段塞进一个 Key。应该按表、模块、分页或业务维度拆分,避免大 Key。
阶段 2:命令执行原理
Redis 快不是一句“内存数据库”就能解释清楚。
flowchart TD
A["客户端请求"] --> B["网络 IO 事件"]
B --> C["解析 Redis 协议"]
C --> D["命令排队"]
D --> E["命令执行线程操作数据结构"]
E --> F["生成响应"]
F --> G["网络返回客户端"]为什么快
| 原因 | 解释 |
|---|---|
| 内存访问 | 大多数操作不需要磁盘随机 IO |
| IO 多路复用 | 少量线程管理大量连接事件 |
| 命令执行模型简单 | 核心命令顺序执行,减少锁竞争 |
| 数据结构优化 | String、Hash、ZSet 等为场景优化 |
| 命令粒度小 | 很多命令是 O(1) 或 O(logN) |
为什么也会慢
| 慢的原因 | 例子 | 后果 |
|---|---|---|
| 大 Key | HGETALL 巨大 Hash | 主线程长时间处理,后续命令排队 |
| 热 Key | 某商品详情被大量访问 | 单节点 CPU 或网络打满 |
| 慢命令 | KEYS *、大范围 ZRANGE | 阻塞其他请求 |
| 长 Lua | 脚本执行过久 | 命令线程被占用 |
| 网络大包 | 一次返回几十 MB | 带宽和客户端解析慢 |
| 持久化压力 | AOF rewrite、RDB fork | 延迟抖动 |
验收问题:
- Redis 单线程为什么还能高并发?
- Redis 6/7 的多线程主要优化什么?
- 为什么一个慢命令会影响其他请求?
- 为什么
KEYS *线上危险?
详细看:命令执行与数据结构原理。
阶段 3:缓存模式和一致性
最常见模式是 Cache Aside。
flowchart TD
A["读请求"] --> B["查 Redis"]
B --> C{"命中"}
C -- "是" --> D["返回缓存"]
C -- "否" --> E["查数据库"]
E --> F{"数据库是否有数据"}
F -- "有" --> G["写缓存并设置 TTL"]
F -- "无" --> H["缓存空值或直接返回"]
G --> I["返回"]
H --> I写操作推荐链路
常见推荐是:先更新数据库,事务提交后删除缓存。
flowchart TD
A["写请求"] --> B["开启数据库事务"]
B --> C["更新 MySQL"]
C --> D["提交事务"]
D --> E["删除 Redis 缓存"]
E --> F{"删除是否成功"}
F -- "成功" --> G["结束"]
F -- "失败" --> H["记录重试或发送补偿消息"]为什么不是先删缓存?
- 先删缓存后,另一个读请求可能读旧数据库。
- 读请求把旧值重新写回 Redis。
- 写请求再更新数据库。
- 结果缓存长期是旧值。
为什么不是直接更新缓存?
- 缓存值可能是复杂聚合结果,更新成本高。
- 并发写入顺序很难保证。
- 删除缓存让下一次读取按数据库事实重建,更稳。
详细看:缓存一致性。
阶段 4:过期删除和内存淘汰
TTL 不是到点立即删除所有 Key。Redis 主要靠惰性删除和定期删除配合。
flowchart TD
A["Key 设置 TTL"] --> B["到达过期时间"]
B --> C{"是否被访问"}
C -- "是" --> D["惰性删除"]
C -- "否" --> E["等待定期抽样检查"]
E --> F["发现过期后删除"]内存满了怎么办
当 maxmemory 到达限制,Redis 会按淘汰策略处理。
| 策略 | 含义 | 适合场景 |
|---|---|---|
| noeviction | 不淘汰,写入报错 | 不允许丢缓存,需要应用兜底 |
| allkeys-lru | 从所有 Key 中淘汰最近少用 | 通用缓存 |
| volatile-lru | 只淘汰设置 TTL 的 Key | 只让缓存 Key 参与淘汰 |
| allkeys-lfu | 淘汰低频访问 Key | 热点明显场景 |
| volatile-ttl | 优先淘汰快过期 Key | TTL 语义强的缓存 |
验收问题:
- Key 到期为什么不一定马上消失?
- 惰性删除和定期删除分别解决什么?
- 内存淘汰和过期删除有什么区别?
- 为什么生产 Key 最好设置 TTL?
详细看:过期删除与内存淘汰原理。
阶段 5:持久化和高可用
Redis 高可用要分清:持久化、复制、故障转移、分片扩容。
| 能力 | 解决什么 | 不解决什么 |
|---|---|---|
| RDB | 某个时间点快照 | 两次快照之间可能丢数据 |
| AOF | 追加命令日志,降低丢失窗口 | 文件变大,需要 rewrite |
| 主从复制 | 读扩展和副本备份 | 主库挂了不会自动切换 |
| Sentinel | 监控主库并自动故障转移 | 不做数据分片 |
| Cluster | slot 分片,扩容量和吞吐 | 单 Key 热点仍在一个 slot |
哨兵和 Cluster 区别
flowchart TD
A["Redis 高可用"] --> B["主从 + Sentinel"]
A --> C["Redis Cluster"]
B --> D["解决主节点故障自动切换"]
B --> E["数据仍是一整份"]
C --> F["按 slot 分片存储"]
C --> G["解决容量和吞吐扩展"]| 对比 | 哨兵模式 | Cluster 模式 |
|---|---|---|
| 数据分片 | 不分片,每组是一整份数据 | 16384 slot 分布在多个主节点 |
| 主要目标 | 自动故障转移 | 分片扩容 + 故障转移 |
| 客户端行为 | 连接主从,感知主从切换 | 需要处理 MOVED、ASK |
| 适合 | 数据量不大但需要高可用 | 数据量大、吞吐高、需要横向扩展 |
| 热 Key | 仍可能压垮主节点 | 单 Key 仍只落一个 slot,仍可能热点 |
验收问题:
- RDB 和 AOF 各自丢数据窗口是什么?
- 主从复制全量和增量怎么理解?
- Sentinel 怎么判断主观下线和客观下线?
- Cluster 的 slot、MOVED、ASK 是什么?
- 为什么 Cluster 不能天然解决单个热 Key?
详细看:主从哨兵 Cluster 全过程原理。
阶段 6:高并发缓存问题
穿透、击穿、雪崩
| 问题 | 本质 | 治理 |
|---|---|---|
| 穿透 | 查询不存在数据,每次都打 DB | 参数校验、空值缓存、布隆过滤器 |
| 击穿 | 热点 Key 失效瞬间打 DB | 互斥锁、逻辑过期、热点预热 |
| 雪崩 | 大量 Key 同时失效或 Redis 故障 | TTL 随机、多级缓存、限流降级 |
布隆过滤器
flowchart TD
A["查询 assetId"] --> B["布隆过滤器判断"]
B --> C{"一定不存在?"}
C -- "是" --> D["直接返回空"]
C -- "否,可能存在" --> E["查 Redis"]
E --> F["未命中再查 MySQL"]布隆过滤器特点:
- 判断不存在一定可信。
- 判断存在只是可能存在。
- 会误判,不会漏判。
- 删除困难,删除多时通常重建。
大 Key 和热 Key
| 问题 | 本质 | 治理 |
|---|---|---|
| 大 Key | 单个 value 太大或集合元素太多 | 拆 Key、分页、限制大小、UNLINK |
| 热 Key | 单个 Key 访问量极高 | 本地缓存、拆 Key、限流、请求合并 |
大 Key 是“单次操作重”,热 Key 是“访问频率高”。一个 Key 可以同时又大又热。
详细看:大 Key 与热 Key 全过程治理、高并发缓存治理。
阶段 7:分布式锁
Redis 分布式锁的基础写法:
set lock:order:1001 token-uuid nx ex 30释放锁必须判断 token:
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end为什么不能直接 del
flowchart TD
A["线程 A 获取锁,过期 30 秒"] --> B["线程 A 业务执行超过 30 秒"]
B --> C["锁自动过期"]
C --> D["线程 B 获取同一把锁"]
D --> E["线程 A 执行 del"]
E --> F["误删线程 B 的锁"]所以锁 value 必须是唯一 token,释放时用 Lua 保证“判断和删除”原子执行。
Redlock 和 Fencing Token
Redlock 试图在多个独立 Redis 节点上获取多数派锁,但它仍然依赖时钟、网络和锁过期假设。对强一致要求极高的场景,不能只靠 Redlock,通常还要用数据库唯一约束、乐观锁、状态机或 Fencing Token。
Fencing Token 是递增令牌。即使旧客户端锁过期后又继续执行,下游也可以根据更小的 token 拒绝旧请求。
详细看:分布式锁、红锁 Redlock、锁扩展点。
阶段 8:生产排查
Redis timeout 排查流程
flowchart TD
A["应用 Redis timeout"] --> B{"是单接口还是全站"}
B -- "单接口" --> C["查该接口 Key 和命令"]
B -- "全站" --> D["查 Redis 实例和网络"]
C --> E["SLOWLOG / bigkeys / hotkeys"]
D --> F["INFO CPU / memory / clients / persistence"]
E --> G{"是否大 Key 或慢命令"}
G -- "是" --> H["拆 Key、分页、禁用危险命令"]
G -- "否" --> I["查连接池、网络、下游阻塞"]
F --> J{"是否内存、持久化、主从异常"}
J -- "是" --> K["扩容、调参、故障转移"]
J -- "否" --> I证据清单
| 证据 | 看什么 |
|---|---|
| 应用日志 | timeout 是读、写、锁还是批量命令 |
| 连接池指标 | 活跃连接、等待连接、最大连接 |
SLOWLOG | 是否有慢命令 |
INFO commandstats | 哪类命令调用多、耗时高 |
MEMORY USAGE | 某个 Key 是否过大 |
--bigkeys | 大 Key 分布 |
--hotkeys | 热 Key 候选 |
INFO memory | used_memory、碎片率、淘汰 |
INFO persistence | RDB/AOF 是否造成抖动 |
INFO replication | 主从延迟、复制状态 |
| Cluster 指标 | slot 分布、单节点热点、MOVED/ASK |
不能做什么
| 错误操作 | 后果 |
|---|---|
线上 KEYS * | 阻塞 Redis 主线程 |
对大集合 HGETALL | 网络和主线程压力巨大 |
直接 DEL 大 Key | 同步释放内存阻塞 |
| timeout 就加连接池 | 可能放大 Redis 压力 |
| Redis 挂了全部打 DB | 数据库雪崩 |
| 分布式锁无 token | 可能误删别人的锁 |
阶段 9:商业场景验收
资产详情缓存
必须做到:
- Key 命名清晰,例如
asset:detail:{assetId}。 - 设置 TTL,并根据业务加随机抖动。
- 更新数据库后删除缓存。
- 删除失败进入重试或 CDC 补偿。
- 查询不存在资产时缓存短 TTL 空值或用布隆过滤器。
热点字典配置
必须做到:
- Redis 缓存全局字典。
- 应用本地缓存短 TTL,降低 Redis 热点。
- 配置变更后发送失效通知。
- 权限、金额、库存这类强一致数据不能照搬本地缓存策略。
分布式任务防重复
必须做到:
SET NX EX获取锁。- value 使用唯一 token。
- Lua 判断 token 后释放。
- 任务耗时超过锁时间要考虑续期或改用调度框架。
- 数据库层仍用唯一约束或状态机兜底。
面试闭环
| 高频问题 | 标准回答 | 深入原理 |
|---|---|---|
| Redis 为什么快 | Redis 面试 | 命令执行与数据结构原理 |
| 单线程为什么高并发 | Redis 面试 | 高并发缓存治理 |
| 穿透击穿雪崩 | Redis 面试 | 缓存问题 |
| 布隆过滤器 | Redis 面试 | 布隆过滤器原理 |
| 大 Key 热 Key | Redis 面试 | 大 Key 与热 Key 治理 |
| 缓存一致性 | Redis 面试 | 缓存一致性 |
| 哨兵和集群区别 | Redis 面试 | 主从哨兵 Cluster 全过程原理 |
| 分布式锁 | Redis 面试 | 分布式锁 |
| Redis容器化怎么保证内存和数据安全 | Redis 面试 | 配置、ACL、RDB/AOF、内存与高可用 |
最终验收题
| 问题 | 合格标准 |
|---|---|
| Redis 是否适合某场景 | 能说清事实源、缓存、临时状态边界 |
| 数据结构怎么选 | 能按访问模式和复杂度选择 |
| Redis 为什么快 | 能说内存、IO 多路复用、命令模型和数据结构 |
| Redis 为什么慢 | 能说大 Key、热 Key、慢命令、持久化、网络 |
| 缓存一致性 | 能画出先写库后删缓存和失败补偿 |
| 穿透击穿雪崩 | 能说本质、流程和治理 |
| 布隆过滤器 | 能说位数组、多哈希、误判、不漏判 |
| 哨兵和 Cluster | 能说高可用和分片扩容区别 |
| 分布式锁 | 能写 SET NX EX、Lua 释放,并说风险 |
| 生产 timeout | 能按应用、连接池、slowlog、bigkeys、info 排查 |
| Redis容器化 | 能解释ACL Secret、/data Volume、RDB/AOF、fork/COW、maxmemory与cgroup余量,以及单容器和高可用的边界 |
本章小结
真正学会 Redis,不是会背命令,而是能把业务场景、数据结构、命令执行、缓存一致性、过期淘汰、持久化、高可用、大 Key、热 Key、分布式锁、生产排查串成闭环。
如果某个问题讲不清,就回到对应知识点页重新看流程图、Demo 和商业场景。Redis 的问题往往不是单点知识不会,而是把缓存、数据库、线程池、网络、持久化、集群和业务一致性割裂开看。
