少女祈祷中...
NEKO
知识库

redis 缓存面试要点

一、缓存总览类

Q1:缓存常见的问题有哪些?

  • 缓存穿透:查不存在的数据,打到 DB。

  • 缓存击穿:热点 key 过期,大量请求打到 DB。

  • 缓存雪崩:大量 key 同时过期,或缓存整体不可用。

  • 缓存与数据库一致性:双写不一致。

  • 热点 key:单个 key 压力过大。

  • 大 key:单个 key 数据量大,操作慢。

Q2:缓存穿透、击穿、雪崩的区别?

问题

原因

特点

穿透

查不存在的数据

缓存和 DB 都没有

击穿

热点 key 过期

单个 key 失效

雪崩

大量 key 同时过期/缓存挂

大面积失效

Q3:缓存和数据库怎么配合?

  • Cache Aside:先读缓存,没有读 DB 并回写。

  • Read/Write Through:缓存层代理 DB 读写。

  • Write Behind:写缓存后异步刷 DB。

  • 最常用 Cache Aside。

二、缓存穿透类

Q4:什么是缓存穿透?

  • 查询一个不存在的数据。

  • 缓存没有,DB 也没有,每次请求都打到 DB。

  • 恶意攻击会压垮 DB。

Q5:怎么解决缓存穿透?

  1. 缓存空值:DB 查不到也缓存 null,设短 TTL。

  2. 布隆过滤器:提前判断 key 是否存在,不存在直接返回。

  3. 参数校验:拦截非法请求。

  4. 限流、黑名单。

Q6:布隆过滤器的原理?

  • 位数组 + 多个哈希函数。

  • 添加:多个哈希位置置 1。

  • 查询:所有哈希位都为 1 才可能存在。

  • 特点:不存在一定准,存在可能误判。

  • 不支持删除(可用 Counting Bloom)。

Q7:缓存空值有什么问题?

  • 占内存,大量不同 key 会撑爆缓存。

  • 要设短 TTL,如 60 秒。

  • 数据后来存在了要能更新。

Q8:布隆过滤器能删除吗?

  • 标准布隆过滤器不能删除。

  • 删除会影响其他元素的判断。

  • 用 Counting Bloom Filter 支持删除,但占更多内存。

三、缓存击穿类

Q9:什么是缓存击穿?

  • 某个热点 key 过期的瞬间,大量请求同时打到 DB。

  • 单个 key,但并发量极大。

  • 和穿透的区别:击穿是 key 存在但过期,穿透是 key 不存在。

Q10:怎么解决缓存击穿?

  1. 互斥锁:只让一个请求查 DB 并回写,其他等待。

  2. 逻辑过期:不设物理 TTL,异步更新。

  3. 热点数据永不过期:后台定时刷新。

  4. 多级缓存:本地缓存 + Redis。

Q11:互斥锁方案怎么实现?

  • 缓存失效时,用 SETNX 抢锁。

  • 抢到的查 DB、回写缓存、释放锁。

  • 没抢到的短暂休眠后重试。

  • 注意锁超时和误删。

Q12:逻辑过期方案怎么实现?

  • value 里存逻辑过期时间,不设物理 TTL。

  • 读到时判断逻辑过期,过期则异步更新。

  • 返回旧数据,保证可用性。

  • 适合热点 key,牺牲短期一致性。

Q13:互斥锁和逻辑过期怎么选?

方案

一致性

可用性

复杂度

互斥锁

强

可能等待

中

逻辑过期

最终一致

高

高

  • 要求强一致用互斥锁,要求高可用用逻辑过期。

四、缓存雪崩类

Q14:什么是缓存雪崩?

  • 大量 key 同时过期,或缓存服务整体不可用。

  • 请求全部打到 DB,DB 崩溃。

  • 比击穿影响面更大。

Q15:怎么解决缓存雪崩?

  1. TTL 加随机值:打散过期时间。

  2. 多级缓存:本地 + Redis。

  3. 缓存高可用:主从、哨兵、Cluster。

  4. 熔断限流:DB 前加保护。

  5. 预热:启动时加载热点。

  6. 永不过期 + 后台刷新。

Q16:TTL 加随机值怎么加?

  • 如基础 3600 秒,加 0~300 秒随机。

  • EXPIRE key (3600 + random(0, 300))。

  • 避免同一时刻大批 key 过期。

Q17:缓存整体挂了怎么办?

  • 多级缓存兜底(本地缓存)。

  • 熔断降级,返回默认值。

  • 限流保护 DB。

  • 快速恢复缓存。

Q18:缓存预热是什么?

  • 系统启动或大促前,提前把热点数据加载到缓存。

  • 避免启动时大量请求穿透。

  • 可定时任务或手动触发。

五、缓存一致性类

Q19:缓存和数据库怎么保证一致?

  • Cache Aside:先更新 DB,再删缓存。

  • 延迟双删:更新 DB,删缓存,延迟再删一次。

  • 订阅 binlog:Canal 监听 DB 变更,更新缓存。

  • 强一致难,通常最终一致。

Q20:为什么是删缓存而不是更新缓存?

  • 更新缓存可能写旧值(并发下)。

  • 删缓存让下次读时重建,更简单。

  • 懒加载,避免无用更新。

Q21:先删缓存还是先更新 DB?

  • 先更新 DB,再删缓存(推荐)。

  • 先删缓存:删后、更新前有请求读到旧值写回缓存,不一致。

  • 先更新 DB:并发读可能读到旧缓存,但下次删后就一致。

Q22:延迟双删是什么?

  1. 更新 DB。

  2. 删缓存。

  3. 延迟几百毫秒再删一次。

  • 应对“更新 DB 后、删缓存前”读到的旧值回写。

  • 延迟时间要大于一次读+回写。

Q23:Canal 订阅 binlog 怎么做?

  • Canal 伪装从库,订阅 MySQL binlog。

  • 解析变更,发 MQ。

  • 消费者更新或删除缓存。

  • 解耦、可靠,但增加组件。

Q24:强一致能做吗?

  • 很难。缓存和 DB 是两个系统。

  • 用分布式锁或事务可接近,但性能差。

  • 通常接受最终一致。

Q25:缓存不一致的影响怎么降低?

  • 设短 TTL,自动过期兜底。

  • 关键数据读主库。

  • 异步补偿,定时校验。

六、热点 key 与大 key 类

Q26:什么是热点 key?

  • 某个 key 被高频访问。

  • 可能导致单节点 CPU 或网络瓶颈。

  • Cluster 下热点 key 落在单个分片。

Q27:怎么发现热点 key?

  • redis-cli --hotkeys(需 LFU 策略)。

  • MONITOR 采样(生产慎用)。

  • 客户端埋点统计。

  • 代理层统计。

Q28:怎么解决热点 key?

  1. 本地缓存:热点放 JVM 本地。

  2. key 拆分:加随机后缀分散到多节点。

  3. 读写分离:从库分担读。

  4. 限流:保护后端。

Q29:什么是大 key?

  • 单个 key 的 value 很大,如大 String、大 Hash、大 List。

  • 危害:操作慢、阻塞主线程、网络拥塞、内存不均。

Q30:大 key 有什么危害?

  • DEL 大 key 阻塞主线程。

  • 网络传输慢,超时。

  • Cluster 下内存分布不均。

  • 持久化和主从同步慢。

Q31:怎么发现大 key?

  • redis-cli --bigkeys:扫描各类型最大 key。

  • MEMORY USAGE key:单 key 内存。

  • SCAN + STRLEN/LLEN/HLEN 自定义。

  • 分析 RDB 文件。

Q32:怎么解决大 key?

  • 拆分:大 Hash 拆多个小 Hash。

  • 异步删除:UNLINK 替代 DEL。

  • 压缩:序列化后压缩。

  • 分片:按字段或范围拆。

Q33:UNLINK 和 DEL 的区别?

  • DEL 同步删除,阻塞主线程。

  • UNLINK 异步删除,后台线程释放。

  • 大 key 用 UNLINK。

七、实战与陷阱题

Q34:缓存一定要设 TTL 吗?

  • 一般要,防止内存无限增长。

  • 热点数据可逻辑过期或永不过期 + 后台刷新。

  • 持久数据不设 TTL 要配淘汰策略。

Q35:缓存更新失败怎么办?

  • 重试 + 补偿。

  • 订阅 binlog 保证最终一致。

  • 短 TTL 兜底。

Q36:缓存和 DB 双写顺序能颠倒吗?

  • 不推荐。先删缓存再更新 DB 易不一致。

  • 推荐先更新 DB 再删缓存。

  • 或用延迟双删、binlog 订阅。

Q37:布隆过滤器能解决击穿吗?

  • 不能。布隆过滤器解决穿透(不存在的数据)。

  • 击穿是热点 key 过期,要用互斥锁或逻辑过期。

Q38:多级缓存怎么设计?

  • L1:本地缓存(Caffeine、Guava),快但容量小。

  • L2:Redis,容量大,共享。

  • L3:DB。

  • 注意本地缓存一致性,用 MQ 广播失效。

Q39:缓存降级是什么?

  • 缓存不可用时,返回默认值或走 DB。

  • 保护核心链路,非核心返回兜底。

  • 配合熔断限流。

Q40:怎么评估缓存命中率?

  • INFO stats 的 keyspace_hits 和 keyspace_misses。

  • 命中率 = hits / (hits + misses)。

  • 低于预期要排查 key 设计或 TTL。

评论