一、缓存总览类
Q1:缓存常见的问题有哪些?
缓存穿透:查不存在的数据,打到 DB。
缓存击穿:热点 key 过期,大量请求打到 DB。
缓存雪崩:大量 key 同时过期,或缓存整体不可用。
缓存与数据库一致性:双写不一致。
热点 key:单个 key 压力过大。
大 key:单个 key 数据量大,操作慢。
Q2:缓存穿透、击穿、雪崩的区别?
Q3:缓存和数据库怎么配合?
Cache Aside:先读缓存,没有读 DB 并回写。
Read/Write Through:缓存层代理 DB 读写。
Write Behind:写缓存后异步刷 DB。
最常用 Cache Aside。
二、缓存穿透类
Q4:什么是缓存穿透?
查询一个不存在的数据。
缓存没有,DB 也没有,每次请求都打到 DB。
恶意攻击会压垮 DB。
Q5:怎么解决缓存穿透?
缓存空值:DB 查不到也缓存
null,设短 TTL。布隆过滤器:提前判断 key 是否存在,不存在直接返回。
参数校验:拦截非法请求。
限流、黑名单。
Q6:布隆过滤器的原理?
位数组 + 多个哈希函数。
添加:多个哈希位置置 1。
查询:所有哈希位都为 1 才可能存在。
特点:不存在一定准,存在可能误判。
不支持删除(可用 Counting Bloom)。
Q7:缓存空值有什么问题?
占内存,大量不同 key 会撑爆缓存。
要设短 TTL,如 60 秒。
数据后来存在了要能更新。
Q8:布隆过滤器能删除吗?
标准布隆过滤器不能删除。
删除会影响其他元素的判断。
用 Counting Bloom Filter 支持删除,但占更多内存。
三、缓存击穿类
Q9:什么是缓存击穿?
某个热点 key 过期的瞬间,大量请求同时打到 DB。
单个 key,但并发量极大。
和穿透的区别:击穿是 key 存在但过期,穿透是 key 不存在。
Q10:怎么解决缓存击穿?
互斥锁:只让一个请求查 DB 并回写,其他等待。
逻辑过期:不设物理 TTL,异步更新。
热点数据永不过期:后台定时刷新。
多级缓存:本地缓存 + Redis。
Q11:互斥锁方案怎么实现?
缓存失效时,用
SETNX抢锁。抢到的查 DB、回写缓存、释放锁。
没抢到的短暂休眠后重试。
注意锁超时和误删。
Q12:逻辑过期方案怎么实现?
value 里存逻辑过期时间,不设物理 TTL。
读到时判断逻辑过期,过期则异步更新。
返回旧数据,保证可用性。
适合热点 key,牺牲短期一致性。
Q13:互斥锁和逻辑过期怎么选?
要求强一致用互斥锁,要求高可用用逻辑过期。
四、缓存雪崩类
Q14:什么是缓存雪崩?
大量 key 同时过期,或缓存服务整体不可用。
请求全部打到 DB,DB 崩溃。
比击穿影响面更大。
Q15:怎么解决缓存雪崩?
TTL 加随机值:打散过期时间。
多级缓存:本地 + Redis。
缓存高可用:主从、哨兵、Cluster。
熔断限流:DB 前加保护。
预热:启动时加载热点。
永不过期 + 后台刷新。
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:延迟双删是什么?
更新 DB。
删缓存。
延迟几百毫秒再删一次。
应对“更新 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?
本地缓存:热点放 JVM 本地。
key 拆分:加随机后缀分散到多节点。
读写分离:从库分担读。
限流:保护后端。
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。
评论