Redis 面试很容易变成命令表:String、List、Hash、Set、ZSet,RDB、AOF,主从、哨兵、Cluster。问题是,真正的线上事故从来不会按命令表出现。
同样是延迟升高,可能是大 key、热 key、慢命令、Pipeline 使用方式、Lua 脚本、AOF fsync、fork COW、输出缓冲、复制阻塞、Cluster 重定向、客户端连接池,甚至只是业务把 Redis 当成了数据库。
所以这篇是「图解 Redis」的收束稿:用 15 轮专家 Review,把 Redis 八股从“会背命令”推进到“能解释成本、能定位故障、能说清边界”。
15 轮 Review:每轮到底在审什么
| 轮次 | 专家视角 | 审查问题 | 通过标准 |
|---|---|---|---|
| 1 | 数据结构 | 是否只背五大类型,不讲内部编码? | 能讲 SDS、listpack、intset、skiplist、rax 和编码切换 |
| 2 | 命令复杂度 | 是否把 O(1) 命令答成永远便宜? | 能把复杂度和 key 大小、返回量、主线程耗时连起来 |
| 3 | String/Bitmap/HLL | 是否把 Bitmap 位偏移、HLL 12KB 等事实讲错? | 能说清 SETBIT offset 小于 2^32 bits,HLL dense 最多约 12KB |
| 4 | Stream | 是否把 XREADGROUP 的 >、历史 ID、$ 混用? |
能讲 PEL、XACK、XCLAIM、XAUTOCLAIM 和挂账恢复 |
| 5 | 过期删除 | 是否把过期说成“到点立刻删”? | 能讲惰性删除、周期删除和过期字典 |
| 6 | 内存淘汰 | 是否把 maxmemory 当成保险丝? | 能讲淘汰策略、不可淘汰 key、碎片和输出缓冲 |
| 7 | 事件循环 | 是否把单线程理解成没有后台线程? | 能区分主线程执行命令和后台 I/O、bio、fork 子进程 |
| 8 | Pipeline/Lua | 是否把 Pipeline 说成让命令变快? | 能讲 Pipeline 降低 RTT,Lua 原子但会阻塞主线程 |
| 9 | RDB | 是否只说快照持久化? | 能讲 fork、COW、恢复速度和快照丢失窗口 |
| 10 | AOF | 是否把 AOF 默认开启、fsync 策略讲错? | 能讲 appendonly no 与 appendfsync everysec 的区别 |
| 11 | AOF Rewrite | 是否把重写理解成压缩原文件? | 能讲子进程重写、增量缓冲和切换过程 |
| 12 | 复制 | 是否只背全量和增量? | 能讲 offset、replication backlog、PSYNC、断线边界 |
| 13 | Sentinel/Cluster | 是否把高可用和分片混为一谈? | 能区分故障转移、槽位、MOVED/ASK、reshard |
| 14 | 缓存实战 | 是否把一致性问题答成单一公式? | 能按写策略、失效策略、业务容忍度和补偿链路讲取舍 |
| 15 | 排查闭环 | 是否只会说 SLOWLOG? | 能从客户端 RT 收敛到命令、key、内存、磁盘、复制和网络 |
Redis 面试的核心不是“某个命令怎么用”,而是三个问题:数据在内存里是什么形态、命令在主线程上走多远、失败时 Redis 留下什么状态。
官方事实基线:这些别背错
下面这些值来自 Redis 8.0 redis.conf 或官方命令文档。线上配置可能被修改,面试时要区分“默认值”和“实例实际值”。
| 主题 | 事实基线 | 面试边界 |
|---|---|---|
| AOF | appendonly no |
Redis 默认不启用 AOF;appendfsync everysec 是启用 AOF 后的默认 fsync 策略 |
| Slowlog | slowlog-log-slower-than 10000 |
单位是微秒,10000 表示 10ms;0 记录所有命令,负数关闭 |
| Hash 编码 | hash-max-listpack-entries 512,hash-max-listpack-value 64 |
field 或 value 任一超过阈值都可能触发编码转换 |
| ZSet 编码 | zset-max-listpack-entries 128,zset-max-listpack-value 64 |
小 ZSet 可用 listpack,变大后进入 skiplist/dict 组合 |
| Set 编码 | set-max-intset-entries 512,另有 listpack entries/value 阈值 |
不要把 Set 永远答成哈希表 |
| Stream 节点 | stream-node-max-bytes 4096,stream-node-max-entries 100 |
Stream 底层是 rax 加 listpack,不是简单链表 |
hz |
默认 10 |
影响周期任务频率,不是越大越好 |
| Bitmap | SETBIT offset 必须小于 2^32 bits |
最大字符串约 512MiB,不是 4GB 字节 |
| HyperLogLog | dense 表示最多约 12KB,标准误差约 0.81% | 低基数 sparse 更小;它不能查成员 |
| Stream claim | XCLAIM 与 XAUTOCLAIM 都是有效命令 |
XAUTOCLAIM 是 6.2 引入的游标式自动扫描,不是 XCLAIM 的旧名 |
官方资料可以从这些入口核对:Redis redis.conf 8.0、SETBIT、HyperLogLog、XCLAIM、XAUTOCLAIM。
面试答题骨架:先讲角色,再讲成本
Redis 题最好按这个顺序回答:
- 先讲业务角色:缓存、计数器、排行榜、消息流、分布式协调,还是主数据存储?
- 再讲内部形态:编码、对象、key 大小、返回量和内存开销。
- 再讲执行成本:是否走主线程、是否会阻塞、是否依赖网络 RTT。
- 再讲故障状态:没 ack、没 fsync、没复制、slot 迁移、缓存失效分别留下什么后果。
- 再讲观测命令:用什么证据证明你的判断。
- 最后讲取舍:延迟、一致性、容量、可恢复性和复杂度谁优先。
只要按这个顺序,Redis 八股就会从“命令问答”变成“系统设计判断”。
五条主线:把全系列串起来
1. 数据结构:命令背后一定有编码
String 不是普通字符串,它有 SDS 和整数/embstr/raw 等编码;Hash、List、ZSet、小 Set 都可能先用紧凑结构,超过阈值后转换。编码一变,内存占用、遍历成本、写入放大都会变。
所以回答“Hash 为什么适合存对象”时,不要只说 field-value。更完整的答案是:小对象用 listpack 紧凑,节省对象开销;一旦字段数或 field/value 长度超过阈值,会转换成 hashtable,内存和遍历成本都变化。
2. 执行模型:单线程不等于所有事情都单线程
Redis 主线程负责命令执行,所以单个慢命令会拖住后面的命令;但持久化、异步关闭、lazy free、部分 I/O 能由后台线程或子进程参与。
Pipeline 降低的是网络往返次数,不会让 HGETALL 一个大 Hash 的主线程成本消失。Lua 脚本保证原子性,但长脚本会阻塞主线程。能把 RTT、命令复杂度和主线程阻塞分开,才算真正理解 Redis 快在哪里、慢在哪里。
3. 内存治理:maxmemory 不是安全感
Redis 内存问题至少分四层:数据本身、对象和编码开销、内存碎片、客户端输出缓冲。设置了 maxmemory 不等于不会出问题,因为不是所有 key 都可淘汰,淘汰策略也可能和业务语义冲突。
Big Key 会让单命令阻塞主线程,Hot Key 会让单节点或单分片被打爆,碎片会让 RSS 比 used_memory 高很多,输出缓冲会在慢客户端或订阅场景里突然涨起来。面试时要把“内存满”拆成这些方向,而不是只说加机器。
4. 持久化与高可用:恢复窗口要讲清
RDB 是快照,恢复快,但两次快照之间可能丢数据;AOF 记录写命令,恢复更细,但文件更大、重写更复杂。Redis 默认不开 AOF,启用 AOF 后默认 fsync 策略是 everysec,这意味着性能和最多约 1 秒数据窗口之间的取舍。
复制要讲 offset 和 replication backlog。主从断开后,如果从库请求的 offset 还在 backlog 内,可以增量同步;否则全量同步。Sentinel 解决故障转移,Cluster 解决分片和路由,不要把两者混成一个“高可用组件”。
5. 缓存实战:一致性没有银弹
缓存一致性题不要直接背“先删缓存再写库”或“延迟双删”。更好的回答是先问业务容忍度:能否短暂不一致、是否有读己之写、是否允许异步修复、是否能用消息补偿、是否需要强一致。
常见工程组合是 cache-aside、设置 TTL、写库后删缓存、失败重试、消息补偿、版本号或逻辑时间防乱序。它们都不是绝对正确,只是在不同成本下减少不一致窗口。
必会观测命令
Redis 排查要能拿证据,而不是靠感觉。
# 基础状态
INFO server
INFO clients
INFO memory
INFO persistence
INFO replication
# 慢命令与延迟
SLOWLOG GET 10
LATENCY DOCTOR
LATENCY LATEST
# key 与对象
TYPE key
OBJECT ENCODING key
MEMORY USAGE key
SCAN 0 MATCH pattern COUNT 1000
# Stream 挂账
XINFO GROUPS stream
XPENDING stream group
XAUTOCLAIM stream group consumer 60000 0-0 COUNT 100
# Cluster 路由
CLUSTER INFO
CLUSTER NODES
CLUSTER KEYSLOT key
注意 KEYS * 不是线上排查命令。它在小实例里看起来方便,在大实例里会阻塞主线程。排查时用 SCAN 系列命令逐步扫描,仍然要控制频率和 COUNT。
20 个高频追问
- Redis 为什么快?是因为单线程,还是因为内存和事件模型?
- 单线程 Redis 为什么也会有后台线程和子进程?
- String 的整数编码、embstr、raw 分别在什么场景出现?
- Hash 什么时候从 listpack 转成 hashtable?
- ZSet 为什么需要 dict 加 skiplist?
- Bitmap 的 offset 上限到底是 bit 还是 byte?
- HyperLogLog 为什么不能判断用户是否存在?
- GEO 为什么说本质上落在 ZSet 上?
- Stream 的 PEL 是什么?消费者重启为什么要读历史 ID?
XCLAIM和XAUTOCLAIM有什么关系?- 过期 key 是否到点立刻删除?
allkeys-lru和volatile-lru的风险差在哪?- Pipeline 为什么不能解决慢命令?
- Lua 为什么原子,却也可能造成延迟尖刺?
- RDB fork 时为什么会出现 COW 内存压力?
- AOF 默认是否开启?
appendfsync everysec代表什么? - AOF rewrite 是不是直接压缩旧 AOF?
- 主从复制什么时候能增量,什么时候必须全量?
- Cluster 的 MOVED 和 ASK 有什么区别?
- 缓存和数据库如何减少不一致窗口?
收束:Redis 面试的底层能力
Redis 面试真正考的不是“你背过多少命令”,而是你能不能把一个命令映射到内部数据结构、主线程成本和故障状态。
如果只能保留一句话:先判断 Redis 在业务里的角色,再看 key 的形态和命令成本,最后用 slowlog、latency、memory、replication、cluster 这些证据收口。
关于十三Tech
我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。
我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。
如果你想继续跟完这套「图解 Redis」,欢迎关注公众号 「十三Tech」。后续会继续按数据结构、底层机制、持久化、高可用和实战排查这条线更新。

