Redis 面试很容易变成命令表:String、List、Hash、Set、ZSet,RDB、AOF,主从、哨兵、Cluster。问题是,真正的线上事故从来不会按命令表出现。

同样是延迟升高,可能是大 key、热 key、慢命令、Pipeline 使用方式、Lua 脚本、AOF fsync、fork COW、输出缓冲、复制阻塞、Cluster 重定向、客户端连接池,甚至只是业务把 Redis 当成了数据库。

所以这篇是「图解 Redis」的收束稿:用 15 轮专家 Review,把 Redis 八股从“会背命令”推进到“能解释成本、能定位故障、能说清边界”。

Redis 面试 15 轮专家 Review 地图

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 noappendfsync 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 512hash-max-listpack-value 64 field 或 value 任一超过阈值都可能触发编码转换
ZSet 编码 zset-max-listpack-entries 128zset-max-listpack-value 64 小 ZSet 可用 listpack,变大后进入 skiplist/dict 组合
Set 编码 set-max-intset-entries 512,另有 listpack entries/value 阈值 不要把 Set 永远答成哈希表
Stream 节点 stream-node-max-bytes 4096stream-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 XCLAIMXAUTOCLAIM 都是有效命令 XAUTOCLAIM 是 6.2 引入的游标式自动扫描,不是 XCLAIM 的旧名

官方资料可以从这些入口核对:Redis redis.conf 8.0SETBITHyperLogLogXCLAIMXAUTOCLAIM

面试答题骨架:先讲角色,再讲成本

Redis 题最好按这个顺序回答:

  1. 先讲业务角色:缓存、计数器、排行榜、消息流、分布式协调,还是主数据存储?
  2. 再讲内部形态:编码、对象、key 大小、返回量和内存开销。
  3. 再讲执行成本:是否走主线程、是否会阻塞、是否依赖网络 RTT。
  4. 再讲故障状态:没 ack、没 fsync、没复制、slot 迁移、缓存失效分别留下什么后果。
  5. 再讲观测命令:用什么证据证明你的判断。
  6. 最后讲取舍:延迟、一致性、容量、可恢复性和复杂度谁优先。

只要按这个顺序,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 个高频追问

  1. Redis 为什么快?是因为单线程,还是因为内存和事件模型?
  2. 单线程 Redis 为什么也会有后台线程和子进程?
  3. String 的整数编码、embstr、raw 分别在什么场景出现?
  4. Hash 什么时候从 listpack 转成 hashtable?
  5. ZSet 为什么需要 dict 加 skiplist?
  6. Bitmap 的 offset 上限到底是 bit 还是 byte?
  7. HyperLogLog 为什么不能判断用户是否存在?
  8. GEO 为什么说本质上落在 ZSet 上?
  9. Stream 的 PEL 是什么?消费者重启为什么要读历史 ID?
  10. XCLAIMXAUTOCLAIM 有什么关系?
  11. 过期 key 是否到点立刻删除?
  12. allkeys-lruvolatile-lru 的风险差在哪?
  13. Pipeline 为什么不能解决慢命令?
  14. Lua 为什么原子,却也可能造成延迟尖刺?
  15. RDB fork 时为什么会出现 COW 内存压力?
  16. AOF 默认是否开启?appendfsync everysec 代表什么?
  17. AOF rewrite 是不是直接压缩旧 AOF?
  18. 主从复制什么时候能增量,什么时候必须全量?
  19. Cluster 的 MOVED 和 ASK 有什么区别?
  20. 缓存和数据库如何减少不一致窗口?

收束:Redis 面试的底层能力

Redis 面试真正考的不是“你背过多少命令”,而是你能不能把一个命令映射到内部数据结构、主线程成本和故障状态。

如果只能保留一句话:先判断 Redis 在业务里的角色,再看 key 的形态和命令成本,最后用 slowlog、latency、memory、replication、cluster 这些证据收口。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。

我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。

如果你想继续跟完这套「图解 Redis」,欢迎关注公众号 「十三Tech」。后续会继续按数据结构、底层机制、持久化、高可用和实战排查这条线更新。

十三Tech公众号二维码