欢迎光临
我们一直在努力

常见的 Redis 面试题

本次导航

  • 为什么快,6.0 之后还算不算单线程
  • 过期 Key 什么时候删,内存满了谁被踢
  • RDB、AOF 怎么选
  • 锁、槽、事务这几问怎么答到点子上
  • 穿透、击穿、大 Key,面试里通常听到哪一层

发车前提醒:下面每题先给能说出口的答法,再补一点别被追问时露怯的细节。

一、Redis 为什么快?现在还是单线程吗?

可以按三层说,别只甩一句“单线程没有锁”。

  • 数据在内存里,读写不走磁盘随机 I/O。
  • 命令执行是单线程,没有多线程改同一份数据的锁竞争,INCR 这类操作天然不会加到一半。
  • I/O 模型合适:epoll 多路复用,一个线程盯着很多连接。协议也简单,解析开销小。
  • 6.0 起可以开 I/O 线程 做网络读写,命令执行仍在主线程。

    所以更准确的说法是:执行模型还是单线程,网络可以并行。

    面试官说“Redis 是单线程的”,你补一句 I/O 线程,面试分+1。

    追问:单线程为什么不会成为瓶颈?内存操作通常是微秒级,瓶颈多在网络和慢命令(KEYS *、超大 HGETALL),不在“一个核算不过来”。

    真把 CPU 打满,先查大 Key、热 Key、Lua 死循环,而不是先上多线程 Redis。

    二、Key 过期了,是马上删掉的吗?

    不是。两套机制一起干活。

    惰性删除:有人访问这个 Key,发现 TTL 过了,当场删,返回空。没人碰的 Key,可以在内存里继续躺着。

    定期删除:后台按频率抽一批带过期时间的 Key,到期的清掉。抽不中的,继续等下一次,或等被访问时惰性删。

    所以会出现:TTL 看着过了,INFO memory 一时半会儿没掉下去。不是 bug。

    和过期容易混的是 淘汰:maxmemory 到了,按策略踢 Key,跟 TTL 没有必然关系。

    缓存场景常见:

    策略什么时候用
    noeviction 默认。写满直接报错,当数据库用时可以
    allkeys-lru 普通缓存,踢最久没人碰的
    allkeys-lfu 你明确知道有长期热点
    volatile-lru 只有设了过期的才允许踢,没 TTL 的当重要数据留着

    CONFIG GET maxmemory-policy 能看到当前值。

    只背 LRU 不够,要能说出 volatile 和 allkeys 的差别。

    三、RDB 和 AOF 怎么选?

    一句话:RDB 是拍照,AOF 是记账。

    • RDB:某一时刻的内存快照,文件小,恢复快。两次快照之间的写入,崩溃就没了。
    • AOF:把写命令追加到日志。appendfsync everysec 最常见,大概最多丢一秒。文件更大,恢复要重放。
    • 混合:AOF 文件前面是 RDB 形态的底,后面跟增量命令。重启时先加载底再重放,兼顾速度和丢失窗口。

    面试里别说“生产必须双开”,缓存丢了能回源 DB,可以只开 RDB,甚至关持久化换性能。

    订单、库存、Stream 这种丢了会心疼的,AOF everysec 更常见。

    SAVE 会卡住主线程,线上用 BGSAVE。fork 出子进程那一下,内存大时可能抖一下,这是追问点。

    四、分布式锁怎么写才不算裸奔?

    最低配:

    SET lock:order_pay node-a NX EX 30

    NX 保证只有一个人抢到,EX 防止进程死了锁永远不放。到这里只能算入门。

    面试官接着会问:业务跑超时了,锁过期,B 抢到了,A 回来 DEL,会不会把 B 的锁删掉?会。所以解锁必须带身份:

    if redis.call('GET', KEYS[1]) == ARGV[1] then
    return redis.call('DEL', KEYS[1])
    else
    return 0
    end

    再往下:时钟、续期、Redlock。单实例 Redis 做缓存互斥、下单防重,SET NX EX + 这段 Lua 就够讲。

    Redlock 要多活独立节点,争议也大,没踩过别主动展开。

    锁不是银弹,扣库存这种 check-then-act,Lua 里读完再写,比锁更干净。

    五、Cluster 的 16384 个槽是什么?

    Cluster 把整个 keyspace 切成 16384 个槽,每个主节点负责一段。Key 落在哪个槽:

    CRC16(key) mod 16384

    客户端算完槽,把命令发到对应节点。

    加节点、迁数据,搬的是槽,不是“把某个前缀的 Key 手动拷过去”。

    多 Key 命令(MGET、SUNION)要求这些 Key 在 同一个槽。

    用花括号包住哈希标签:order:{1001}:pay 和 order:{1001}:items 都按 1001 算槽,才能一起操作。

    从库、Sentinel 是另一套题:主从复制解决读扩展和备份,Sentinel 负责主挂了选新主。

    Cluster 自己带故障转移和分片,别把三个词搅成一个“高可用”。

    六、事务能回滚吗?Pipeline 算事务吗?

    不能回滚,Pipeline 也不是事务。

    • Pipeline:客户端把一串命令打包发出去,少几次网络往返。执行时别人可以插进来。
    • MULTI / EXEC:EXEC 的时候这串命令连续跑完,中间不插别的客户端。某条因为类型错失败了,旁边那条照样提交。
    • Lua:能在服务端写 if/else,执行期间同样不插队。失败也不会把已经写成功的命令撤掉。

    入队时参数个数都写错,EXEC 会整单放弃(EXECABORT)。

    执行期对字符串做 INCR,只炸那一条。

    面试里把这两种失败分开,比背“Redis 没有事务”有用。

    需要“读到库存再决定扣不扣”,用 Lua,别指望 MULTI 里下一条能看到上一条的返回值——返回值要等 EXEC 才一次性给你。

    七、穿透、击穿、雪崩,大 Key、热 Key

    这组题喜欢混着问。先把对象说清:

    发生了什么
    穿透 查一个库里从来没有的 ID,缓存没有,DB 也没有,每次空跑
    击穿 一个热点 Key 刚好过期,所有人打到 DB
    雪崩 大批 Key 同一时刻过期,或 Redis 挂了
    大 Key 单个 Key 体积或元素特别多,删、迁、HGETALL 都会卡住别人
    热 Key 单个 Key 被打得特别凶,一个核、一块网卡先着

    应对在面试里说到能落地的那一层就行:

    • 穿透:空值短 TTL;流量脏就上布隆(BF.EXISTS),过滤器说没有就别查库
    • 击穿:SET NX EX 只放一个人回源;热点逻辑过期,先把旧值吐出去再刷新
    • 雪崩:TTL 加随机数;Redis 挂了靠本地缓存和接口降级,不是再调一个过期时间
    • 大 Key:拆;删除用 UNLINK 别 DEL
    • 热 Key:本地缓存、拆成多个副本随机读。Redis 8.6 可用 HOTKEYS START / GET 找谁最热

    项目里这些怎么排障、怎么改代码,这里先挖个坑,我们下期再说。

    八、缓存和数据库哪个先写?

    面试常考 Cache-Aside:

    读:先 Redis,没有再 DB,再回填 Redis。

    写:先更新 DB,再删 Redis 的 Key(让下次读回填),不要先改缓存再改库——库失败了缓存就是脏的。

    删缓存也会有并发窗口:A 删完还没写完,B 读到旧值又 SET 回去。

    面试说到“先库后删缓存 + 可接受的短暂不一致”就够,强一致要上别的方案,那是系统设计问题。

    主从延迟也会读到旧缓存或旧库,读要走主、或者接受短暂落后,别假装复制是同步的。

    九、问自己几个问题

  • 用自己的话讲清:命令执行单线程,I/O 可以多线程。
  • SET lock:x a NX EX 5,另开窗口再抢一次;再用 Lua 按值删除,换一个值删,应该是 0。
  • CONFIG GET maxmemory-policy,说出当前策略满了会怎样。
  • 写一个带 {user1001} 的两个 Key,解释它们为什么能在 Cluster 里一起 MGET。
  • 下期预告:Redis 完结篇,把线上真正扎手的那些问题放到项目路径里:热点商品、大 Hash、缓存和 DB 打架、瞬间打满连接。


    本次导航结束,欢迎 关注、点赞、转发。

    赞(0)
    未经允许不得转载:171主机测评 » 常见的 Redis 面试题
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址