专家级 Redis 体系:多级缓存架构、Key 设计规范、数据建模、降级容灾、可观测性、安全 ACL、容量规划、Redis 7新特性,附 37 道高频面试题完整解析。
五、专家:生产级 Redis 体系
1. Redis 使用边界
| 适合 Redis 的场景 | 不适合 Redis 的场景 |
|---|---|
| 热点缓存、计数器、排行榜 | 强事务核心账务 |
| 分布式锁、限流 | 大规模离线分析 |
| 短期状态(TTL 天然适配) | 长期海量冷数据 |
| 轻量消息流(Stream) | 高可靠金融消息 |
2. Key 设计规范
推荐格式:业务域:实体:标识:属性
text
user:1001:profile
product:1001:detail
order:20260424:1001
lock:order:1001
rate:api:login:ip:192.168.1.10
原则:
- 可读性优先,控制 key 长度。
- 统一分隔符(冒号)。
- 缓存类 key 必须考虑 TTL。
- 避免一个 key 无限增长。
- Cluster 多 key 操作使用 hash tag:
cart:{1001}:items
3. 数据建模能力
建模步骤:
text
先确定查询路径
-> 再选择数据结构
-> 再设计 key
-> 再确定 TTL 和一致性策略
-> 最后评估大 Key、热 Key、集群跨槽风险
| 场景 | 数据结构 | 示例 |
|---|---|---|
| 购物车 | Hash | HSET cart:1001 product:2001 2 |
| 信息流时间线 | ZSet | ZADD feed:1001 timestamp post:9001 |
| 签到 | Bitmap | SETBIT sign:1001:202604 23 1 |
| UV 统计 | HyperLogLog | PFADD uv:20260424 user:1001 |
4. 多级缓存架构
text
请求 -> 本地缓存(Caffeine) -> Redis -> MySQL
| 层级 | 延迟 | 容量 | 一致性 |
|---|---|---|---|
| L1 本地缓存 | ~ns | 受 JVM 堆限制 | 最弱,各实例独立 |
| L2 Redis | ~ms | 大 | 较好 |
| L3 数据库 | ~10ms | 最大 | 最强 |
本地缓存失效通知(Redis Pub/Sub):
text
数据更新 -> 删除 Redis 缓存
-> PUBLISH cache:invalidate product:1001
-> 各实例订阅消息并清除本地缓存
5. 客户端工程实践
连接池配置要点:
text
最大连接数 / 最小空闲连接数 / 最大等待时间 / 连接超时 / 读写超时 / 健康检查
超时和重试原则:
- 读请求可以适当重试。
- 写请求重试必须保证幂等。
- 分布式锁、扣库存不能盲目重试。
序列化建议: 统一使用 JSON 或 Protobuf,禁止 JDK 默认序列化。
6. 可观测性体系
核心指标:
| 类别 | 指标 |
|---|---|
| 性能 | QPS、P99 延迟、慢查询数量 |
| 内存 | used_memory、mem_fragmentation_ratio、evicted_keys |
| 连接 | connected_clients、blocked_clients、rejected_connections |
| 持久化 | latest_fork_usec、rdb_last_bgsave_status、aof_delayed_fsync |
| 复制 | master_link_status、replication lag |
| 集群 | cluster_state、slot 状态、fail 节点数量 |
命中率计算:
text
hit_rate = keyspace_hits / (keyspace_hits + keyspace_misses)
需要告警的情况:
- 内存使用率持续超过 80%。
- evicted_keys 持续增长。
- blocked_clients 大于 0。
- 复制延迟超过阈值。
- AOF/RDB 最近一次执行失败。
7. 安全治理
bash
# ACL 控制
ACL SETUSER app on >strongPassword ~app:* +get +set +del +expire
# 禁用危险命令
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
高危命令:FLUSHALL / FLUSHDB / KEYS / CONFIG / SHUTDOWN / EVAL
基本要求:
- 禁止 Redis 直接暴露公网。
- 开启认证,使用 ACL。
- 开启 TLS(如需要)。
- 控制客户端来源 IP。
8. 容量规划
text
建议实例内存 = 业务数据量 × 1.3 至 2.0
示例:业务数据约 20GB → 元数据碎片预留 30% → COW 峰值预留 30% → 建议约 32GB
生产建议:
- 单实例不要无限放大,过大实例 fork 和恢复成本高。
- 设置
maxmemory,明确淘汰策略。 - 预留故障恢复和持久化空间。
9. 降级和容灾设计
| 场景 | 降级方案 |
|---|---|
| 缓存不可用 | 走本地缓存或数据库限流查询 |
| 排行榜失败 | 返回上一次快照 |
| 限流 Redis 失败 | 使用本地限流兜底 |
| 分布式锁失败 | 拒绝关键写操作或走数据库唯一约束 |
10. 故障演练清单
建议定期演练:Redis 主节点宕机 / Replica 延迟升高 / Sentinel 故障转移 / Cluster 节点下线 / 大 Key 删除 / 缓存雪崩 / 热 Key 高并发 / 客户端连接池耗尽
十、Redis 新版本特性(7.x)
1. Function(替代 Lua EVAL)
bash
FUNCTION LOAD "#!lua name=mylib\nredis.register_function('myfunc', function(keys, args) return redis.call('GET', keys[1]) end)"
FCALL myfunc 1 user:1001
| 维度 | Lua EVAL | Function |
|---|---|---|
| 持久化 | 重启后丢失 | 随数据持久化 |
| 复制 | 需所有节点缓存 | 自动复制 |
| 管理方式 | SCRIPT LOAD / EVALSHA | FUNCTION LOAD / FCALL |
2. Multi-part AOF
AOF 从单文件改为多文件,rewrite 更高效,降低磁盘 I/O 抖动。
3. Sharded Pub/Sub
bash
SSUBSCRIBE channel:1001
SPUBLISH channel:1001 "hello"
消息只发到对应 slot 的节点,适合 Cluster 环境。
4. 其他改进
EXPIRETIME/PEXPIRETIME:返回 key 的绝对过期时间戳。- ACL v2:支持 Pub/Sub 频道权限控制。
CLUSTER SHARDS:替代CLUSTER SLOTS,更清晰的分片信息。
九、37 道高频面试题全解
基础类
1. Redis 支持哪些数据结构?
String / Hash / List / Set / ZSet / Bitmap / HyperLogLog / Geo / Stream
2. String 和 Hash 存对象有什么区别?
| 维度 | String JSON | Hash |
|---|---|---|
| 修改单个字段 | 需整体反序列化写回 | 直接 HSET |
| 整体读写 | 方便 | 需 HGETALL |
3. key 过期后会立即删除吗?
不会。Redis 用惰性删除 + 定期删除 + 内存淘汰三种机制处理过期 key。
4. Redis 为什么适合做缓存?
基于内存 / 支持 TTL / 支持丰富数据结构 / 高并发 / 支持淘汰策略
缓存类
5. 什么是缓存穿透?怎么解决?
查询不存在的数据。解决:缓存空值 / 布隆过滤器 / 参数校验限流
6. 什么是缓存击穿?怎么解决?
热点 key 过期,大量请求瞬间打到数据库。解决:互斥锁重建 / 逻辑过期 / 热点 key 永不过期
7. 什么是缓存雪崩?怎么解决?
大量 key 同时过期或 Redis 整体不可用。解决:TTL 加随机值 / 热点预热 / 多级缓存 / 限流降级
text
区别:
穿透 → 查不存在的数据
击穿 → 单个热点 key 过期
雪崩 → 大量 key 同时过期或缓存服务整体不可用
8. Redis 和 MySQL 如何保证数据一致性?
常用做法:先更新 MySQL,再删除 Redis,配合重试 / 消息队列 / binlog 监听(Canal)+ TTL 兜底。
9. 为什么常用"先更新数据库,再删除缓存"?
缓存是数据库的派生数据,先更新 DB 保证事实准确,删除缓存让下次请求从 DB 加载最新值。
并发类
10. Redis 分布式锁如何实现?
bash
SET lock:order:1001 requestId NX EX 10
释放必须用 Lua 脚本(原子校验+删除)。工程中推荐 Redisson(提供看门狗续期、可重入锁等)。
11. 为什么释放锁要用 Lua?
GET + DEL 两步非原子,可能误删其他线程的锁。Lua 脚本在 Redis 中原子执行。
12. Redisson 的看门狗机制是什么?
不指定固定过期时间时,Redisson 启动后台续期任务,每隔一段时间延长锁过期时间,业务完成后主动释放。
13. Redis 事务和 Lua 有什么区别?
| 维度 | Redis 事务 | Lua 脚本 |
|---|---|---|
| 原子性 | EXEC 中命令连续执行 | 整个脚本原子执行 |
| 条件判断 | 较弱,需配合 WATCH | 很强,可写复杂逻辑 |
| 适合场景 | 简单批量命令 | 库存扣减、限流、锁释放 |
架构类
14. Redis 为什么快?
基于内存 + 单线程命令执行(无锁竞争)+ I/O 多路复用 + 高效数据结构(SDS/skiplist)+ 轻量协议
15. Redis 真的是单线程吗?
命令执行主路径是单线程,RDB/AOF rewrite 会 fork 子进程,Redis 6+ 支持多线程 I/O。
16. RDB 和 AOF 有什么区别?
RDB 是快照(恢复快,可能丢数据),AOF 是写命令日志(数据更安全,通常 everysec 最多丢 1 秒)。
17. 主从复制的过程是什么?
全量复制(RDB)→ 增量复制(写命令)→ 断线重连部分重同步(backlog)
18. Sentinel 如何实现故障转移?
监控 → 主观下线 → 客观下线 → 选举 Leader Sentinel → 选最优 Replica 提升 → 通知客户端
19. Redis Cluster 如何分片?
text
CRC16(key) % 16384 → 16384 个 slot → 每个节点负责一部分
20. 什么是 hash slot?
Cluster 的数据分片单位,方便扩缩容时只迁移部分 slot。
21. 什么是 hash tag?
user:{1001}:profile 和 user:{1001}:orders 使用相同的 hash tag {1001},落到同一个 slot,支持多 key 操作。
性能类
22. 什么是大 Key?有什么危害?
value 很大或集合元素数量非常多的 key。危害:阻塞主线程 / 传输慢 / 删除耗时 / 主从复制压力大。
23. 什么是热 Key?怎么解决?
极高频访问的 key。解决:本地缓存 / key 拆分多副本 / 多副本读 / 限流
24. Redis 慢查询如何排查?
bash
SLOWLOG GET 10
LATENCY DOCTOR
常见原因:KEYS * / 大 Key 全量读取 / 大规模 DEL / AOF fsync 抖动
25. Pipeline 有什么作用?
减少客户端和 Redis 之间的网络往返次数,适合批量写入/查询。注意不保证原子性。
26. Redis 内存淘汰策略有哪些?
noeviction / allkeys-lru / volatile-lru / allkeys-lfu / volatile-lfu / volatile-ttl / allkeys-random
缓存场景常用 allkeys-lru 或 allkeys-lfu。
专家类
27. 如何做 Redis 容量规划?
text
建议实例内存 = 业务数据量 × 1.3~2.0
预留元数据、碎片、COW 内存、副本成本
28. RDB/AOF rewrite 为什么可能导致 Redis 抖动?
fork 需要复制页表,数据量越大耗时越高;COW 额外内存升高;磁盘 I/O 升高影响 fsync。
29. Redis 主从切换会丢数据吗?
可能会。异步复制下 Master 未同步到 Replica 的数据在故障转移后丢失。WAIT 和 min-replicas 可降低概率。
30. Redis Cluster 扩容和迁移时要注意什么?
迁移前检查集群健康 / 避免高峰期迁移 / 关注大 Key / 确认客户端支持 MOVED 和 ASK / 迁移后检查 slot 均衡。
31. Redis 可以当消息队列吗?
可以,但要看可靠性要求。Stream 支持持久化 + 消费者组 + ACK,适合轻量异步任务。核心交易消息建议使用专业 MQ。
32. Redis 线上延迟突然升高,如何系统排查?
text
SLOWLOG GET → LATENCY DOCTOR → INFO memory(evicted_keys)
→ INFO persistence(latest_fork_usec)→ INFO clients(blocked_clients)
→ redis-cli --bigkeys → 机器 CPU/内存/磁盘/网络
33. 如何设计 Redis 的生产监控和告警?
覆盖:QPS / P99 延迟 / 命中率 / evicted_keys / 慢查询 / 内存使用率 / 复制延迟 / 集群状态 / AOF 状态
34. 如何从源码角度解释 Redis 命令为什么会阻塞?
text
Redis 命令执行在单线程主路径。
KEYS * / HGETALL 大 Hash / DEL 大 key / 复杂 Lua 均会占用主线程。
UNLINK 将内存释放交给后台线程,减少阻塞。
35. 什么是 Redis 内存碎片?如何处理?
碎片率 = used_memory_rss / used_memory。>1.5 偏高,>2.0 需处理。
处理:activedefrag yes(在线整理)或 MEMORY PURGE(手动触发)。
36. Redis Function 和 Lua EVAL 有什么区别?
Function 支持持久化和自动复制,按名称调用,管理更规范。Lua EVAL 每次发送脚本文本或 SHA,重启后脚本丢失。
37. 如何用 Redis 实现令牌桶限流?
用 Hash 存储 tokens 和 last_time,Lua 脚本原子计算:
lua
local elapsed = now - last_time
tokens = math.min(capacity, tokens + elapsed * rate / 1000)
if tokens >= requested then
tokens = tokens - requested
return 1 -- 放行
else
return 0 -- 拒绝
end
| 方案 | 突发支持 | 平滑限流 |
|---|---|---|
| 固定窗口 | 窗口边界突刺 | 弱 |
| 滑动窗口 | 较好 | 较好 |
| 令牌桶 | 允许突发 | 好 |
| 漏桶 | 不允许突发 | 最好 |
八、学习路线
入门阶段
Redis 概念 / Key 命名规范 / 5 大基础数据结构 / TTL / 基础缓存
提高阶段
Cache Aside / 穿透击穿雪崩 / 分布式锁 / Lua / Stream 消息队列
进阶阶段
RDB/AOF / 主从复制 / Sentinel / Cluster / 内存淘汰 / 性能排查
专家阶段
数据建模 / Key 设计 / 底层结构 / 事件循环 / 容量规划 / 安全治理 / 故障演练 / 源码阅读
十一、核心主线总结
text
数据结构怎么用
-> 缓存问题怎么解决
-> 并发原子性怎么保证
-> 消息和异步任务怎么处理
-> 数据可靠性怎么保证
-> 高可用和水平扩展怎么设计
-> 性能问题怎么排查和优化
-> 生产风险怎么监控、降级和演练
-> 源码原理怎么解释线上问题
Redis 的核心能力:
text
业务建模能力 → 正确的数据结构和 key 设计
高并发治理能力 → 缓存、限流、锁、热点、异步任务
可靠性设计能力 → 持久化、复制、一致性、故障窗口
架构扩展能力 → Sentinel、Cluster、扩缩容、跨槽约束
生产运维能力 → 监控、告警、安全、容量规划、故障演练
源码理解能力 → 用内部机制解释延迟、阻塞、内存和数据一致性问题
本文是《Redis 知识体系》系列第三篇,聚焦专家实战与面试题。
第一篇:《Redis 数据结构与工程实战》→ 9大数据结构 × 11个高频场景
第二篇:《Redis 原理深度解析》→ 持久化/主从/Sentinel/Cluster/性能排查