从最终的物理表现来看,它们确实非常相似:缓存层“失效”了,大量请求直接涌向数据库,导致数据库压力剧增。
但如果从运维排查和系统行为的角度来看,它们在表现上其实有几个非常核心的细微差别:
能否“自我修复”
这是两者最显著的区别:
- 缓存击穿(Hot Key Expired):是可以自我修复的。只要数据库扛住了那一波瞬间的冲击,第一个请求成功把数据从数据库读出来并回写到缓存,后续的请求就会重新命中缓存,数据库压力立即消失。
- 缓存穿透(Non-existent Data):是无法自我修复的。因为数据库里根本没这个数据,缓存永远不会被填充(除非你手动缓存了空对象)。只要攻击者不停手,或者业务逻辑没改,数据库就会一直处于高压状态。
数据的“虚实”
- 缓存击穿:用户是在抢购一个真实存在的爆款商品,只是正好那一秒缓存到期了。
- 缓存穿透:用户(或黑客)是在查询一个根本不存在的 ID(比如 ID 为
-1或随机长字符串),这些请求本身就是“无效”的。
请求的“集中度”
- 缓存击穿:通常是万箭穿心,即海量请求都在盯着同一个特定的热点 Key。
- 缓存穿透:通常是漫天撒网,攻击者可能会利用脚本随机生成成千上万个不存在的 Key,让你的缓存层完全拦截不住。
总结对比表
| 特性 | 缓存击穿 (Breakdown) | 缓存穿透 (Penetration) |
|---|---|---|
| 数据库里有数据吗? | 有,只是缓存刚过期 | 没有,永远找不到 |
| 请求的 Key 数量 | 通常是单个热点 Key | 通常是大量随机、不存在的 Key |
| 持续时间 | 极短(回写完缓存即停止) | 持续(直到请求停止或拦截) |
| 常见症状 | 数据库 CPU 瞬间飙升,又迅速恢复 | 数据库 CPU 持续高位,直到服务挂掉 |
| 核心解药 | 互斥锁(SETNX)、逻辑过期 | 布隆过滤器、缓存空对象 |
所以,虽然它们都让数据库“很受伤”,但缓存击穿是“阵痛”,而缓存穿透是“持续性伤害”。在实际排查中,如果你看到数据库压力一直在查同一个不存在的 ID,那就是穿透;如果你看到瞬间波动且数据其实是有的,那就是击穿。