
目录一缓存穿透1.是什么2.怎么防止二缓存击穿1.是什么2.怎么防止三缓存雪崩1.是什么2.怎么防止总结一缓存穿透1.是什么其实很好理解一般正常的逻辑是前端发起查询先查redisredis命中就返回数据如果没有就去查mysql查到后写入redis里并返回。现在假设有一个黑客想要搞垮这个网站。它一直发送请求查询一个不存在的商品ID或者其它东西他们既不存在于redis中也不存在于mysql中。这就造成了一个后果请求砸向 Redis→ \rightarrow→没命中→ \rightarrow→请求全部穿透到 MySQL→ \rightarrow→MySQL 查半天发现也没有→ \rightarrow→无法回写 Redis因为没数据。100 万个这种恶意请求直接绕过缓存防御全部死磕在 MySQL 上。MySQL 瞬间 CPU 爆满、连接池耗尽直接瘫痪整个网站跟着一起崩溃。2.怎么防止有两种方法当mysql发现一个ID不存在时不要什么都不做。我们在redis里为这个ID存一个特殊的空值。并设置一个较短的过期时间。那么接下来这个较短的时间中再用这个ID来攻击时redis就会直接返回null请求就被拦截在缓存层了但是这个方案只要黑客不断变换攻击ID照样会穿透这只能防止某个ID被大量请求的情况。这才是真正有效的布隆过滤器这是一个极其高效的二进制数据结构。在请求到达Redis之前先让布隆过滤器在最外层站岗。我们把数据库里所有已存在的商品ID全部通过哈希算法映射到布隆过滤器上他只占极小的内存。当黑客带着 ID -999 连进来时布隆过滤器一算冷冰冰地告诉你“这个 ID 绝对不存在于数据库中” 连 Redis 都不用查直接当场拒绝该请求。二缓存击穿1.是什么击穿和穿透不一样穿透是查不存在的数据击穿是查一个非常热门的真实数据。如果一个数据在redis里的访问量是每秒20w次。这个key在被疯狂访问的时候刚好到了它在redis里设置的过期时间TTL。就在这一秒钟这个Key突然在Redis里蒸发了而那每秒20w次的请求瞬间扑了个空。20w个并发请求在同一秒内发现Redis没数据只能同时涌入到Mysql里去查这条数据面对这么多的并发服务器瞬间宕机。2.怎么防止不设置过期时间。对于这种预知到的超热点数据比如春晚活动、双十一 iPhone 秒杀页面在后台直接不给它设置过期时间让它永久留在内存里。等活动结束了后台再手动执行脚本异步把它们删掉。互斥锁Mutex Lock当 Redis 没命中时不写命令让所有请求一拥而上。而是让第一个到达的请求去“抢一把互斥锁”比如用 SETNX 抢锁。抢到锁的那个幸运儿代表大家去 MySQL 查数据然后把数据写回 Redis。而剩下的 19.9 万个请求抢不到锁就原地睡 50 毫秒然后重试。当它们醒来重试时Redis 里已经有那个幸运儿写回的数据了直接完美命中三缓存雪崩1.是什么如果说击穿是“精准爆破”打死一个点那么雪崩就是“大面积塌方”整座大山砸下来。通常有两种原因会引发雪崩原因 1 运营人员做活动在昨晚零点批量导入了 100 万个商品数据并且顺手给它们设置了相同的过期时间比如全是 1 小时。结果到了今天凌晨 1 点这 100 万个 Key 在同一秒钟集体过期。原因 2 Redis 服务器由于硬件故障、断电或者网线被踢掉直接挂机宕机了。灾难 整个系统的缓存屏障瞬间消失空了。海量的用户请求失去了 Redis 的保护如同雪崩引发的洪水全量砸在底层的 MySQL 数据库上。MySQL 哪怕再强也会在一秒内被连环冲跨导致整个公司的业务全部瘫痪。2.怎么防止随机过期时间Jitter原理 绝对不要让大批量的 Key 拥有相同的过期时间。我们在设置过期时间时加上一个随机干扰值。做法 比如原本要设 1 小时3600秒我们改成 3600 rand(1, 300) 秒。这样这 100 万个 Key 就会在 1 小时到 1 小时零 5 分钟之间慢慢地分批过期请求被均匀拉长MySQL 完全可以轻松撑住。主从架构与哨兵集群原理 单机版 Redis 太脆弱了。在线上必须部署 Redis 哨兵模式Sentinel 或者 Cluster 集群。效果 一旦主机Master断电挂了哨兵会像“急救队长”一样在 10 秒内自动把备用机Slave提拔为新的主机继续支撑流量不让系统崩盘。总结穿透查的是不存在的数据黑客恶意乱搞。防御靠 布隆过滤器 或 缓存空对象。击穿查的是超热点的数据刚好过期。防御靠 互斥锁SETNX 或 热点数据永不过期。雪崩成千上万的 Key 集体过期或 Redis 直接宕机。防御靠 随机过期时间 和 高可用集群。