尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Redis 缓存三大问题与防护实战:穿透、雪崩、击穿

Redis 缓存三大问题与防护实战:穿透、雪崩、击穿 缓存几乎是每个高并发系统的标配但很多线上故障恰恰出在缓存层。本文不堆概念直接拆解生产中最常见的三类缓存问题——穿透、雪崩、击穿给出可落地的成因分析与防护代码配套一张对比速查表方便排查时对照。一、缓存穿透查的都是不存在的数据成因请求查询的 key 在缓存和数据库里都不存在每次都会打到数据库。如果有大量这类请求无论是业务误用还是恶意构造数据库会被直接拖垮。防护方案方案一缓存空值对查不到的结果也写一份短过期时间的空标记避免重复回源。publicStringgetUser(Stringkey){Stringcachedredis.get(key);if(cached!null){// 空标记用特殊前缀区分returnNULL_FLAG.equals(cached)?null:cached;}StringdbValuserMapper.selectById(key);if(dbValnull){// 缓存空标记过期时间短防止长期占用redis.setex(key,60,NULL_FLAG);returnnull;}redis.setex(key,3600,dbVal);returndbVal;}方案二布隆过滤器前置在访问缓存前用布隆过滤器拦截一定不存在的 key适合 key 空间可枚举的场景。// 写入时同步加入过滤器bloomFilter.put(key);// 查询前先判断if(!bloomFilter.mightContain(key)){returnnull;}两种方案可以叠加布隆过滤器拦掉绝大多数非法 key空值缓存兜住偶发漏网。二、缓存雪崩大量 key 同时失效成因一批缓存 key 设置了相同的过期时间到点后集中失效瞬间所有请求回源数据库形成峰值冲击。或者是缓存服务整体不可用请求全部穿透到数据库。防护方案错开过期时间给基础 TTL 加一个随机偏移避免集体到期。intbase3600;intjitternewRandom().nextInt(600);// 0~600 秒随机redis.setex(key,basejitter,value);多级缓存本地缓存如 Caffeine作为一级Redis 作为二级。即使 Redis 层抖动本地缓存仍能扛住一部分读请求给数据库留出缓冲。服务降级与限流在入口层对回源数据库的并发做限流配合熔断保证数据库不会被瞬时洪峰打挂。三、缓存击穿单个热点 key 失效成因某个被高频访问的热点 key 过期瞬间大量并发同时发现缓存没了一起回源等于把数据库在该 key 上“击穿”。和雪崩的区别是击穿是单点雪崩是面。防护方案互斥锁重建只有一个线程去回源其余线程等待结果。publicStringgetHotKey(Stringkey){Stringvalredis.get(key);if(val!null)returnval;StringlockKeylock:key;// 仅一个线程能获取锁去回源if(redis.setnx(lockKey,1,30)){try{valloadFromDb(key);redis.setex(key,3600,val);}finally{redis.del(lockKey);}}else{// 未抢到锁短暂等待后重试Thread.sleep(50);returngetHotKey(key);}returnval;}逻辑过期不真删除value 里带一个逻辑过期时间字段过期后由异步线程重建业务读永远命中缺点是短期可能读到旧数据适合一致性要求不极端的场景。四、三类问题对比速查问题触发条件影响范围核心防护缓存穿透key 在库里也不存在单 key 持续打库空值缓存 布隆过滤器缓存雪崩大量 key 同时失效全局性峰值冲击随机 TTL 多级缓存 限流降级缓存击穿单个热点 key 失效单热点被打穿互斥锁重建 逻辑过期五、上线前的防护清单所有回源路径必须有限流或单飞singleflight保护禁止无保护直接查库。空值缓存的 TTL 要短且需和业务正常数据区分标记避免污染。热点 key 的 TTL 不要设成整点错峰 逻辑过期双保险。监控缓存命中率与数据库 QPS 突增命中率骤降往往先于故障出现。布隆过滤器预计误判率要评估key 空间增长后及时扩容。小结穿透、雪崩、击穿三者常被混为一谈关键区分在“影响范围”穿透是查不存在的数据雪崩是大面积同时失效击穿是单点热点失效。落地时穿透靠空值 布隆过滤器雪崩靠错峰 TTL 与多级缓存击穿靠互斥锁或逻辑过期。把这些防护做成通用组件比每次出故障再救火省力得多。
返回列表