最终的物理表现来看,它们确实非常相似:缓存层“失效”了,大量请求直接涌向数据库,导致数据库压力剧增。

但如果从运维排查系统行为的角度来看,它们在表现上其实有几个非常核心的细微差别:

能否“自我修复”

这是两者最显著的区别:

  • 缓存击穿(Hot Key Expired):是可以自我修复的。只要数据库扛住了那一波瞬间的冲击,第一个请求成功把数据从数据库读出来并回写到缓存,后续的请求就会重新命中缓存,数据库压力立即消失。
  • 缓存穿透(Non-existent Data):是无法自我修复的。因为数据库里根本没这个数据,缓存永远不会被填充(除非你手动缓存了空对象)。只要攻击者不停手,或者业务逻辑没改,数据库就会一直处于高压状态。

数据的“虚实”

  • 缓存击穿:用户是在抢购一个真实存在的爆款商品,只是正好那一秒缓存到期了。
  • 缓存穿透:用户(或黑客)是在查询一个根本不存在的 ID(比如 ID 为 -1 或随机长字符串),这些请求本身就是“无效”的。

请求的“集中度”

  • 缓存击穿:通常是万箭穿心,即海量请求都在盯着同一个特定的热点 Key。
  • 缓存穿透:通常是漫天撒网,攻击者可能会利用脚本随机生成成千上万个不存在的 Key,让你的缓存层完全拦截不住。

总结对比表

特性缓存击穿 (Breakdown)缓存穿透 (Penetration)
数据库里有数据吗?,只是缓存刚过期没有,永远找不到
请求的 Key 数量通常是单个热点 Key通常是大量随机、不存在的 Key
持续时间极短(回写完缓存即停止)持续(直到请求停止或拦截)
常见症状数据库 CPU 瞬间飙升,又迅速恢复数据库 CPU 持续高位,直到服务挂掉
核心解药互斥锁(SETNX)、逻辑过期布隆过滤器、缓存空对象

所以,虽然它们都让数据库“很受伤”,但缓存击穿是“阵痛”,而缓存穿透是“持续性伤害”。在实际排查中,如果你看到数据库压力一直在查同一个不存在的 ID,那就是穿透;如果你看到瞬间波动且数据其实是有的,那就是击穿。