Skip to content

Redis 高频三题:标准答案与危险追问

这篇笔记沉淀 3 个高频 Redis 面试题的:

  • 标准口述答案
  • 高频追问
  • 危险追问与更稳的回答方式

适合在 /grill-me 之后做二刷,也适合作为 30 秒版 -> 2 分钟版 -> 连环追问 的复习底稿。

关联项目:

  • [[黑马点评]]

1. Redis 为什么快,单线程为什么还能快

标准答案

Redis 快主要有几个原因。第一,它是基于内存读写的,避免了磁盘随机 IO,这是最基础的性能来源。第二,它内部很多操作都是基于高效的数据结构完成的,命令执行路径比较短。第三,它在网络层用了 IO 多路复用,可以用一个线程高效监听大量连接,不需要一个连接开一个线程,减少了线程资源浪费。第四,Redis 执行命令的核心模型是单线程串行执行,这样避免了多线程下的锁竞争和频繁上下文切换,内部实现也更简单。

所以单线程还能快,不是因为单线程天然快,而是因为 Redis 的瓶颈很多时候不在 CPU 执行命令,而在内存访问和网络 IO。再加上命令执行本身很轻,单线程反而能减少并发编程的额外成本。要注意,IO 多路复用解决的是“如何高效处理大量网络连接”,不等于 Redis 变成了多线程并发执行命令,真正的命令执行还是单线程串行的。

高频追问

  • 你一直说 Redis 快是因为内存,那是不是只要基于内存就一定快?
  • IO 多路复用到底解决了什么问题?
  • 为什么 IO 多路复用不等于 Redis 变成多线程并发执行命令?
  • select、poll、epoll 有什么区别?Redis 为什么更常提 epoll?
  • 既然是单线程,为什么不会成为瓶颈?
  • Redis 6 为什么引入多线程?
  • Redis 的单线程说法准确吗?

危险追问与稳答

危险追问 1:只答“因为在内存里”够不够?

不够。内存只是性能基础,Redis 真正快是多个因素叠加:基于内存避免磁盘随机 IO,内部数据结构高效、命令路径短,网络层用 IO 多路复用高效处理大量连接,命令执行层保持单线程减少锁竞争和线程切换。所以 Redis 快不是单点原因,而是整条请求处理链路都比较轻。

危险追问 2:IO 多路复用和多线程到底区别在哪?

IO 多路复用解决的是网络连接监听问题,也就是一个线程怎么同时感知很多 socket 的读写事件。它只是把“哪些连接准备好了”高效交给 Redis,而不是说多个线程一起执行业务命令。Redis 真正执行命令时,核心还是单线程串行处理,所以多路复用是并发监听,不是并发执行。

危险追问 3:Redis 6 为什么引入多线程?

Redis 6 引入多线程,主要是为了优化网络 IO 读写这一层,而不是把核心命令执行彻底改成多线程并发。随着并发连接越来越多,网络收发开始成为瓶颈,所以 Redis 把部分 IO 工作拆给多线程处理,但命令执行这层仍然尽量保持串行,避免复杂锁竞争。也就是说,Redis 6 不是否定单线程,而是在网络层补齐瓶颈。

易错点

  • 不要把 IO 多路复用 说成 并发执行命令
  • 不要只答 因为在内存里
  • 不要把 Redis 6 多线程说成 命令执行完全并行

2. 缓存穿透、击穿、雪崩分别是什么,你项目里怎么解决

标准答案

缓存穿透是指查一个根本不存在的数据,请求打到 Redis 没命中,打到数据库也没命中,但这样的请求还在反复进来,最终把数据库打得很重。我的做法是空值缓存加短 TTL,把数据库查不到的结果也缓存起来,后续请求直接拦截。对于更分散、更像恶意攻击的场景,也可以用布隆过滤器先做存在性判断,不过它有误判率,维护成本也更高。

缓存击穿是指某个热点 key 失效了,瞬间大量并发请求同时回源数据库。这个场景下我项目里更倾向逻辑过期方案,因为热点数据最怕的不是短时间旧值,而是大量线程一起阻塞把应用和数据库拖垮。逻辑过期的做法是发现过期后只让一个线程抢锁异步重建,其他线程先返回旧值。

缓存雪崩是指大量 key 在同一时间集体过期,或者 Redis 整体不可用,大量请求同时打到数据库。这个问题我会组合治理,比如给 TTL 加随机值避免同时过期,Redis 做主从、哨兵或者集群提高可用性,系统层再加限流、降级、熔断,必要时配合本地缓存或热点预热一起兜底。

高频追问

  • 空值缓存为什么能防穿透?
  • 空值缓存有什么缺点?
  • 布隆过滤器为什么适合防穿透?有什么问题?
  • 缓存击穿和雪崩的区别是什么?
  • 为什么热点 key 更适合逻辑过期,而不是互斥锁?
  • 拿不到锁为什么不阻塞等待?
  • 如果逻辑过期返回旧值,那不是脏数据吗?
  • 雪崩为什么不能只靠随机 TTL?
  • 你项目里最终为什么选这个方案?

危险追问与稳答

危险追问 1:空值缓存能完全防住穿透吗?

不能。空值缓存更适合拦截重复查询同一个不存在 key 的场景。如果是大量分散的恶意请求,空值缓存效果会变差,还会占用额外缓存空间。这种情况下更适合加布隆过滤器,先在缓存层前面做存在性判断,把明显不存在的数据直接拦掉,减少回源压力。

危险追问 2:逻辑过期不是会返回旧值吗?为什么还适合热点场景?

逻辑过期确实会在重建窗口内返回旧值,所以它不适合强一致要求高的场景。但热点场景里最怕的往往不是短时间旧值,而是大量请求同时回源把数据库和线程池拖垮。对于商铺详情、展示类信息这类能容忍短暂旧值的场景,逻辑过期是更合理的取舍。它本质上是用短暂不一致换系统吞吐和可用性。

危险追问 3:缓存雪崩为什么不能只靠随机 TTL?

因为雪崩本质上是系统级风险,不是只靠缓存层一个动作就能解决。随机 TTL 只能缓解集体过期,Redis 主从和哨兵解决的是缓存高可用,但如果 Redis 整体不可用,大量请求还是会回源数据库。所以必须配合限流、熔断、降级,必要时再结合本地缓存、多级缓存、热点预热,把数据库保护住。也就是说,雪崩治理一定是组合拳。

易错点

  • 不要把 击穿雪崩 混成一类
  • 不要把 返回旧值 说成 返回空值
  • 不要只说 随机 TTL,忘了系统层保护

3. 逻辑过期方案为什么适合热点数据,为什么不直接让线程阻塞等重建

标准答案

逻辑过期适合热点数据,是因为热点数据并发很高,一旦缓存失效,如果让大量线程都阻塞等待重建,应用线程池很容易被占满,数据库压力也会瞬间上来,最后系统整体可用性会出问题。相比之下,热点数据很多时候是可以容忍几秒旧值的,所以更适合用逻辑过期这种方案。

它的核心流程是:缓存里除了数据本身,还带一个逻辑过期时间。请求进来先查缓存,如果没过期直接返回;如果过期了,不是立刻删 key,也不是让所有线程都回源数据库,而是只让一个线程抢锁去异步重建缓存,其他线程直接返回旧值。抢到锁的线程在重建前一般还会做一次 double check,避免重复重建。

这套方案的本质是用可接受的短暂不一致,换系统的高并发能力和可用性。它不保证强一致,保证的是最终一致性,也就是重建完成后,缓存最终会和数据库重新对齐。

高频追问

  • 什么样的数据适合逻辑过期?
  • 什么样的数据不适合逻辑过期?
  • 逻辑过期和真正的 TTL 过期有什么区别?
  • 为什么要返回旧值,而不是返回空或者报错?
  • 为什么只让一个线程重建?
  • double check 是在防什么?
  • 逻辑过期怎么保证最终一致性?
  • 逻辑过期的风险是什么?
  • 如果异步重建线程挂了怎么办?
  • 逻辑过期和互斥锁方案你怎么选?

危险追问与稳答

危险追问 1:为什么不让线程等一会儿,等新值回来不是更一致吗?

理论上等待会更一致,但热点场景下代价太大。因为热点 key 一旦失效,请求量通常非常集中,如果大量线程都阻塞等待重建结果,应用线程池很容易被占满,数据库压力也会瞬间放大。相比之下,很多热点读场景是能容忍几秒旧值的,所以更合理的做法是只让一个线程重建,其余线程先返回旧值,优先保系统吞吐和可用性。

危险追问 2:逻辑过期怎么保证最终一致性?如果异步线程失败了,不就一直旧了吗?

逻辑过期保证的是最终一致,不是强一致。正常情况下,过期后会有一个线程抢锁回源数据库并重写缓存,这样缓存最终会和数据库重新对齐。如果异步重建失败,确实可能导致旧值持续存在,所以工程上要加重试、监控告警,必要时人工干预。也就是说,最终一致性的前提是重建链路本身要可靠。

危险追问 3:是不是所有缓存都可以用逻辑过期?

不是。逻辑过期适合的是高并发读多写少、并且业务能容忍短时间旧值的数据,比如商铺详情、推荐信息、统计类展示数据。像账户余额、库存最终扣减、支付状态这类强一致要求高的数据,就不适合逻辑过期,因为这些场景不能接受旧值带来的业务风险。

易错点

  • 不要把 逻辑过期 说成 Redis 原生 TTL
  • 不要忽略 double check
  • 不要把 最终一致性 说成 强一致
  • 不要把它泛化到所有缓存场景

三题主线关系

这三题不是孤立的,而是同一条缓存面试主线:

  1. Redis 为什么快 先说明 Redis 作为高性能缓存中间件,本身为什么能扛并发。
  2. 穿透 / 击穿 / 雪崩 再说明即使 Redis 很快,缓存体系还是会出现什么问题。
  3. 逻辑过期为什么适合热点数据 最后落到具体治理策略,解释为什么在热点高并发读场景下,要用“短暂不一致换吞吐”的方案。

一句话串起来:

Redis 本身性能强,但缓存体系仍会遇到穿透、击穿、雪崩等问题;在热点 key 失效这种高并发读场景里,逻辑过期是一个典型的用短暂一致性换系统可用性的治理方案。