Redis的缓存雪崩、缓存穿透、缓存击穿是什么?怎么解决?
目录一、先分清穿透、击穿、雪崩到底差在哪二、缓存穿透防的是 “不存在的请求”1. 问题本质2. 我的项目里是这么解决的① 参数校验 拦截② 缓存空值③ 布隆过滤器高风险场景用三、缓存击穿防的是 “热点 key 瞬间过期”1. 问题本质2. 我的两种方案各有适用场景方案一互斥锁强一致性首选方案二逻辑过期高并发场景首选四、缓存雪崩防的是 “大面积失效或 Redis 挂了”1. 问题本质2. 我在项目里的系统级防护① 给 TTL 加随机值② Redis 高可用③ 多级缓存兜底④ 限流熔断五、我的总结怎么根据场景选方案最后说句实在的做 Java 后端开发谁没被 Redis 缓存问题坑过高峰期一个请求进来Redis 没查到直接打穿到数据库瞬间 CPU 飙满、连接池打满接口直接雪崩。这背后往往就是缓存穿透、击穿、雪崩这三个问题在搞鬼。今天我就用最直白的方式把这三个问题掰开揉碎讲清楚它们的本质区别、风险点以及你在项目里可以直接抄的解决方案。一、先分清穿透、击穿、雪崩到底差在哪很多人面试都分不清这三个其实一句话就能说清楚穿透查的东西本来就不存在。击穿单个热点东西刚好过期了。雪崩一堆东西同时过期了或者 Redis 直接挂了。你可以想象成一个超市穿透你要买一个店里根本不卖的东西问一次服务员一次问十次十次都得去仓库查仓库迟早被你烦死。击穿店里最热门的可乐卖完了成千上万的人同时问服务员服务员都得去仓库拿瞬间就挤爆了。雪崩店里所有的饮料同时卖完了或者仓库直接炸了所有人都挤向唯一的通道整个店直接瘫痪。问题核心特征典型场景主要风险常见方案缓存穿透查询的数据根本不存在恶意请求、错误参数、爬虫数据库被无效请求打满参数校验、缓存空值、布隆过滤器缓存击穿单个热点 key 失效瞬间并发回源热门商品、热点店铺、活动库存数据库被热点流量冲垮互斥锁、逻辑过期、热点预热缓存雪崩大量 key 同时失效或 Redis 故障批量导入缓存、整点统一过期、节点宕机请求成片压垮数据库和下游随机 TTL、高可用、多级缓存、限流熔断二、缓存穿透防的是 “不存在的请求”1. 问题本质你请求的数据Redis 里没有数据库里也没有。每次请求都得打到数据库数据库查不到也没法回写缓存结果就是数据库被一堆无效请求打满。典型场景恶意爬虫、参数校验不严比如用户用id-1疯狂请求你的接口。2. 我的项目里是这么解决的我一般用三层防护成本低效果好① 参数校验 拦截先在入口把明显非法的请求挡掉比如负数 ID、格式错误的手机号、空参数不让它们进缓存层。② 缓存空值数据库查不到时把空字符串也缓存起来设置一个很短的 TTL比如 2 分钟。这样下次再查同一个不存在的 IDRedis 直接返回空不会再打数据库。// 伪代码 Shop shop getById(id); if (shop null) { // 把空值写入Redis2分钟过期 stringRedisTemplate.opsForValue().set(key, , 2, TimeUnit.MINUTES); return null; }③ 布隆过滤器高风险场景用如果你的接口经常被攻击请求量特别大那就用布隆过滤器。把所有可能存在的 key 提前存进去请求来时先判断不存在的直接拒绝连 Redis 都不碰。缺点是要提前规划数据量有极微小的误判率。三、缓存击穿防的是 “热点 key 瞬间过期”1. 问题本质某个超级热门的 key比如秒杀商品、爆款店铺在高峰期刚好过期成千上万的请求同时发现缓存失效一起回源数据库直接把数据库冲垮。2. 我的两种方案各有适用场景方案一互斥锁强一致性首选只让一个请求去查库重建缓存其他请求要么等待重试要么直接返回旧数据。// 伪代码 String lockKey lock:shop: id; boolean isLock tryLock(lockKey); if (!isLock) { // 没拿到锁休眠一下重试或者直接返回旧数据 Thread.sleep(50); return queryWithMutex(id); } // 拿到锁了去查库重建缓存 try { Shop shop getById(id); stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), 30, TimeUnit.MINUTES); } finally { unLock(lockKey); }优点是数据一致性好缺点是会有短暂等待对用户体验有一点点影响。方案二逻辑过期高并发场景首选不设物理 TTL而是在缓存里存一个逻辑过期时间。请求来了先看逻辑时间没过期直接返回如果过期了先返回旧数据再开个新线程去后台异步更新缓存。优点是用户体验丝滑完全无等待缺点是会短暂返回过期数据适合一致性要求不高的热点读场景。四、缓存雪崩防的是 “大面积失效或 Redis 挂了”1. 问题本质大量 key 同时过期或者 Redis 集群整体宕机导致所有请求瞬间打到数据库形成级联故障。2. 我在项目里的系统级防护雪崩不能靠单一方案必须多管齐下① 给 TTL 加随机值把过期时间打散避免所有 key 同时在整点失效。// 伪代码 // 基础30分钟加0-10分钟随机值 int random new Random().nextInt(10); stringRedisTemplate.opsForValue().set(key, value, 30 random, TimeUnit.MINUTES);② Redis 高可用用主从、哨兵或者集群部署避免单点故障导致整个缓存层挂掉。③ 多级缓存兜底在 Redis 前面再加一层本地缓存比如 Caffeine。Redis 出问题时热点数据还能靠本地缓存扛一波流量。④ 限流熔断给接口加上限流比如每秒只允许 100 个请求回源数据库超过的直接降级返回默认数据保护数据库不被冲垮。五、我的总结怎么根据场景选方案普通业务 key缓存空值 合理 TTL解决穿透问题。热点读 key互斥锁或逻辑过期解决击穿问题。系统层面随机 TTL Redis 高可用 限流降级预防雪崩。记住没有银弹只有最合适的组合拳。最后说句实在的缓存这三个问题本质上都是高并发下的 “木桶效应”—— 缓存层一旦出现短板所有压力都会瞬间传导到数据库。所以写缓存代码的时候别只想着怎么存进去多想想它过期了怎么办、挂了怎么办、被恶意攻击了怎么办。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2584013.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!