Skip to content

Redis 面试连环追问(口述链) ​

一条真实面试里很常见的追问路径。目标不是再学一遍知识点,而是:从上到下能连续讲 8~15 分钟,每一环都能接住下一问。

详细专题仍看分区文章;本页是「串起来怎么说」。

练习方式:先看稿 → 只看小标题 → 脱稿。卡在哪一环,回对应专题补。


整条链(先看地图) ​

text
Redis
 ↓ 为什么快
 ↓ 单线程
 ↓ Redis 6
 ↓ 数据结构
 ↓ ZSet 排行榜
 ↓ 缓存
 ↓ 缓存穿透
 ↓ 缓存击穿
 ↓ 分布式锁
 ↓ SET NX
 ↓ 为什么要 EX / PX
 ↓ 为什么要唯一 value
 ↓ Lua
 ↓ Redisson
 ↓ 看门狗
 ↓ 缓存一致性
 ↓ MySQL
 ↓ MQ

1. Redis 是什么?(开场) ​

Redis 是基于内存的高性能键值库。项目里我主要用它做缓存、分布式锁、计数、限流和临时状态,不是当业务主库替代 MySQL。

展开一句即可,别一上来背全部命令。

专题:基础原理 · 总览


2. 为什么快? ​

口述四条就够:

  1. 内存读写,比磁盘快几个数量级
  2. 高效数据结构(哈希、跳表等)
  3. I/O 多路复用,单线程也能扛很多连接
  4. 命令简单,多数复杂度低

加一句边界:

快不等于不会慢。大 Key、热 Key、KEYS *、慢命令一样能把实例拖垮。


3. 单线程?那不会成为瓶颈吗? ​

说的「单线程」主要指命令执行在一个主线程里串行跑,所以单命令原子、不用复杂锁。
但进程里不只有这一个线程;而且一个慢命令会堵住后面所有请求。

生产禁忌:KEYS *、胡乱 HGETALL 超大 Hash、同步 DEL 超大 Key(改用 SCAN / UNLINK)。


4. Redis 6 呢?不是多线程了吗? ​

Redis 6 可以把部分 网络读写 交给 I/O 线程并行,减轻读写 socket 的压力。
命令执行仍然主要在主线程,业务上还是按「命令串行」来设计,不能假设多个写逻辑在服务端并行交错执行同一把锁。


5. 常用数据结构?举个例子 ​

快速带过五件套 + 特殊类型:

类型我怎么用
String缓存 JSON、计数、SET NX 锁
Hash对象字段、可部分更新
List简单队列、最新列表
Set去重、共同好友
ZSet排行榜、延迟任务
Bitmap / HLL签到、近似 UV
Stream轻量消息流

6. ZSet 怎么做排行榜? ​

Key 是榜单,member 是用户/内容,score 是热度或分数。ZINCRBY 更新分数,ZREVRANGE 取 TopN。

可追问时补:

  • 日榜/周榜用不同 Key
  • 榜太大要裁剪
  • 并列分数靠 member 或次级排序策略
  • 底层小数据压缩结构,大数据 跳表 + 字典(范围查询友好)

专题:数据类型 · 实战·排行榜


7. 缓存一般怎么用? ​

读多写少的热点数据放 Redis。典型路径:先查缓存,未命中查 MySQL,回写缓存并设过期(最好加随机,防雪崩)。

架构演进可一句带过:单 Redis → 热点加本地缓存(Caffeine)→ 保护 DB。

专题:缓存问题 · 缓存架构


8. 缓存穿透是什么?怎么防? ​

查根本不存在的数据:缓存没有,DB 也没有,每次都打穿到 DB(常被恶意扫库)。

防:

  • 缓存空值(短 TTL)
  • 布隆过滤器(说不存在就一定不存在;说存在可能误判)

9. 缓存击穿呢?和穿透有什么区别? ​

热点 Key 刚好过期,瞬时大量请求打到 DB。
穿透是「数据本来就不存在」;击穿是「热点存在但缓存空窗」。

防:

  • 互斥锁:只有一个线程回源,其它等待重试
  • 逻辑过期:先返回旧值,后台异步刷新

(若再问雪崩:大量 Key 同时过期或 Redis 挂了 → 过期随机 + 限流降级 + 高可用。)


10. 分布式锁为什么用 Redis? ​

多实例下 JVM 锁管不住。Redis 单线程执行命令 + SET key value NX PX,适合做跨进程互斥(库存预扣、防重复提交、定时任务抢主等)。

边界:金融级强一致可考虑 ZK;多数业务 Redisson + DB 乐观锁兜底即可。

专题:分布式锁


11. SET NX 是什么意思? ​

NX = Not eXists:Key 不存在才设置成功 → 抢到锁;已存在则失败 → 没抢到。

完整推荐写法:

text
SET lock_key unique_value NX PX 30000

不要拆成先 SETNX 再 EXPIRE。


12. 为什么一定要 EX / PX(过期)? ​

防止持锁进程宕机后死锁。
若 SETNX 成功后、还没 EXPIRE 就挂了,锁永远不释放。所以 NX 和 PX 必须同一条命令原子完成。


13. 为什么 value 必须唯一? ​

防止误删别人的锁。
场景:A 超时锁过期 → B 拿到锁 → A 业务结束执行 DEL,会把 B 的锁删掉。
做法:value = UUID(+ 线程标识);释放前校验「是不是我的」,是才删。


14. 那为什么还要 Lua? ​

「先 GET 判断再 DEL」在客户端是两步,中间仍可能被打断,极端下仍会误删。
用 Lua 把校验 + 删除做成一次原子脚本 交给 Redis 执行。Redisson 的 unlock 就是这么干的。

Lua 也常用于:库存判断+扣减、限流窗口计数。专题:并发


15. 为什么还要 Redisson?自己 SET 不够吗? ​

手写锁能讲清原理,生产更稳的是 Redisson:可重入、解锁封装、看门狗续期、少踩续期和误删的坑。


16. 看门狗是什么? ​

业务可能超过初始过期时间。看门狗在持锁期间周期性续期,避免锁提前释放导致并发不安全。
进程挂了,看门狗也停,锁最终过期,避免永久死锁。
unlock 放 finally;正常释放后不再续期。


17. 缓存和 MySQL 怎么保证一致? ​

常用 Cache Aside:先更新 MySQL,再删除缓存(让下次读取回源)。
一般不采用「先更新缓存再写库」或「写库后更新缓存」当默认方案——并发下更容易脏数据,且写多读少时浪费。

并发下仍可能有极短不一致;普通业务可接受。要求更高:

  • 延迟双删(慎用,要懂窗口)
  • Canal 听 MySQL Binlog → 发 MQ → 消费者删缓存,靠重试做最终一致

专题:缓存架构实战


18. 这里 MQ 扮演什么角色?(链的收口) ​

分清两件事,面试官常混着问:

A. 用 Redis 当 MQ 行不行?

  • Pub/Sub:不能当可靠队列(不在线即丢、不持久)。
  • Stream:轻量可以,消费组/ACK 有了;订单等核心链路仍优先专业 MQ。

B. 缓存一致性链路里的 MQ:

  • 不是用 Redis 替代 MQ,而是 Binlog → MQ → 删 Redis,保证删缓存可重试、最终一致。

专题:消息


一口气口述模板(约 2~3 分钟压缩版) ​

Redis 是内存键值库,我们主要做缓存和分布式锁。快是因为内存、高效结构和 I/O 多路复用;命令在主线程串行,所以单命令原子,但慢命令会堵全库。Redis 6 的多线程主要帮网络读写,命令执行仍偏单线程。
类型里排行榜用 ZSet。缓存先 Redis 后 MySQL,防穿透用空值和布隆,防击穿用互斥或逻辑过期,过期加随机防雪崩。
分布式锁用 SET key uuid NX PX:NX 互斥,PX 防死锁,uuid 防误删,释放用 Lua 原子校验删除。生产用 Redisson,看门狗负责续期。
和 MySQL 一致一般是先更新库再删缓存;要更稳就 Binlog + MQ 异步删缓存。Redis Pub/Sub 不当可靠 MQ,核心异步还是专业消息中间件,Stream 只适合轻量场景。


自测清单 ​

按链脱稿时,每一环能否用 一两句话 答完,并主动引出下一环:

  • [ ] 为什么快 → 自然说到单线程
  • [ ] 单线程 → 自然说到 Redis 6 边界
  • [ ] 数据结构 → 主动举 ZSet 排行榜
  • [ ] 缓存 → 自己区分穿透 / 击穿
  • [ ] 锁 → NX、PX、唯一 value、Lua、Redisson、看门狗一条线
  • [ ] 一致性 → MySQL 怎么写、MQ 在一致性里干什么、和「Redis 当 MQ」有何不同

卡哪一环,回上面链接的专题页补,再回到本链重练。

返回:Redis 总览