09.缓存问题
文章目录
问题: 请分别定义缓存穿透、缓存击穿、缓存雪崩,并针对每种问题给出至少两种解决方案(如布隆过滤器、互斥锁、随机过期时间等)
👇 点击展开/折叠 面试背诵模板(建议先背这个)
一、缓存穿透(Cache Penetration)
定义:查询一个不存在于缓存和数据库中的key,每次请求都绕过缓存直达数据库,造成数据库压力剧增,常被恶意攻击利用(如查询不存在的用户ID)。
解决方案:
① 布隆过滤器(Bloom Filter):在缓存层前置一个布隆过滤器,存储所有可能存在的数据key。查询时先经过布隆过滤器判断key是否存在,若不存在则直接返回,不访问数据库。注意布隆过滤器存在误判率(假阳性),需根据业务容忍度调整哈希函数数量和位图大小。
② 缓存空值(Cache Null Value):当数据库查询返回空结果时,仍将该key存入缓存,value设为null并设置较短的过期时间(如5分钟)。此方案简单有效,但需注意大量空值key占用内存,适合攻击key数量有限的场景。
二、缓存击穿(Cache Breakdown)
定义:某个高频访问的热点key在缓存过期失效的瞬间,大量并发请求同时发现缓存失效,全部穿透到数据库,造成数据库瞬时压力激增。
解决方案:
① 互斥锁(Mutex Lock):使用Redis的SETNX命令,仅允许一个线程/进程去数据库重建缓存,其他线程等待或轮询。重建完成后释放锁,其他线程直接从缓存读取。关键点:设置锁的过期时间(防止重建线程意外崩溃导致死锁),且锁的value需唯一标识(防止误删)。
② 逻辑过期(Logical Expiration):缓存中不设置物理过期时间(TTL),而是在value中存入一个逻辑过期时间字段。读取时若发现逻辑过期,异步线程去数据库刷新缓存,当前请求仍返回旧数据。此方案无需等待锁,响应快,但数据短暂不一致,适合对实时性要求不高的场景。
三、缓存雪崩(Cache Avalanche)
定义:缓存中大量key在同一时间段集中过期,或缓存服务节点整体宕机,导致大量请求同时绕过缓存直接打到数据库,引发数据库过载甚至宕机。
解决方案:
① 随机过期时间(Random TTL):为每个key设置过期时间时,在基础时间上增加一个随机偏移量(如基础时间 + 随机0~300秒),避免大量key在同一时刻集体失效。
② 高可用集群部署:使用Redis主从+哨兵模式或Redis Cluster,避免单节点故障导致整个缓存不可用。同时配置多级缓存(如本地缓存Ehcache + Redis),即使Redis宕机,本地缓存仍能兜底部分流量。
③ 熔断降级与限流:当数据库访问延迟升高或错误率激增时,触发熔断机制(如Hystrix),快速失败返回默认值或友好提示;同时限制每秒通过的请求数(限流),保护数据库不被瞬时流量冲垮。
四、三种异常对比总结
| 问题 | 根本原因 | 危害特征 | 核心解决方向 |
|---|---|---|---|
| 缓存穿透 | 查询不存在的数据 | 恶意攻击,大量请求直达DB | 前置过滤(布隆过滤器)或空值缓存 |
| 缓存击穿 | 单个热点key瞬间失效 | 瞬时高并发穿透 | 互斥锁重建或异步逻辑过期 |
| 缓存雪崩 | 大量key同时失效/节点宕机 | 流量洪峰压垮DB | 分散失效时间 + 高可用架构 + 限流熔断 |