| @@ -48,7 +48,3 @@ | |||
| 48 | 48 | ### 小结 | |
| 49 | 49 | ||
| 50 | 50 | 抓住“查询缓存的 key 不存在”这个共性,再区分**数据源里到底有没有**以及**是单点还是大面积**,三种场景和对应方案就能自然对上号,不必去死记名字。 | |
| 51 | - | ||
| 52 | - | --- | |
| 53 | - | ||
| 54 | - | > 注:本文档原始仓库在一次数据迁移中丢失,仅数据库预览保留了开头至“查询缓存的key不存在”一段(原文)。此分割线以上、该句之后的内容为根据原文主题与结构重建补全,供参考,可自行订正。 | |
ruanun / cache_problem.md
Last active 2 months ago
ruanun revised this gist 2 months ago · 12cd4db
1 file changed, 4 deletions
ruanun revised this gist 1 year ago · a508aae
1 file changed, 54 insertions
| @@ -0,0 +1,54 @@ | |||
| 1 | + | ## 缓存击穿/穿透/雪崩的简单总结 | |
| 2 | + | ||
| 3 | + | - 我对这几个概念不太喜欢,因为名字容易记混、定义的细节也容易混淆。 | |
| 4 | + | ||
| 5 | + | - 下面按照我的方式做的总结,不再纠结这几个名字,而是重点阐述问题的维度和问题的实质,以便于更好的记忆、区分和应对方案设计。 | |
| 6 | + | ||
| 7 | + | ### 问题的根本原因 | |
| 8 | + | ||
| 9 | + | 这几个工程问题根本原因的共性:查询缓存的key不存在。 | |
| 10 | + | ||
| 11 | + | 而“key 不存在”可以拆成两个维度来看: | |
| 12 | + | ||
| 13 | + | 1. **数据本身在数据源里就不存在**:无论查多少次,缓存都不会有,请求每次都会落到数据库(甚至被恶意构造成海量不同的 key)。 | |
| 14 | + | 2. **数据在数据源里存在,但此刻缓存里没有**:可能是还没加载、也可能是刚好过期失效,请求短时间内集中打到数据库。 | |
| 15 | + | ||
| 16 | + | 围绕这两个维度,再叠加“单个 key”还是“大批量 key”的规模差异,就对应到了那三个被起了名字的场景。 | |
| 17 | + | ||
| 18 | + | ### 三种场景的实质与区分 | |
| 19 | + | ||
| 20 | + | | 场景 | 实质 | 规模 | 数据源中是否存在 | | |
| 21 | + | | --- | --- | --- | --- | | |
| 22 | + | | 穿透 | 查一个数据源里根本不存在的 key,缓存永远挡不住 | 单个/大量 | 不存在 | | |
| 23 | + | | 击穿 | 某个热点 key 过期的瞬间,大量并发同时回源 | 单个热点 key | 存在 | | |
| 24 | + | | 雪崩 | 大批 key 在同一时间集中失效,或缓存整体不可用 | 大量 key | 存在 | | |
| 25 | + | ||
| 26 | + | 一句话区分: | |
| 27 | + | - **穿透**:数据本来就没有 → 缓存形同虚设。 | |
| 28 | + | - **击穿**:数据有,但“一个热点 key”在失效瞬间被并发击垮。 | |
| 29 | + | - **雪崩**:数据有,但“一大片 key”同时失效 / 缓存宕机,压力整体压向 DB。 | |
| 30 | + | ||
| 31 | + | ### 应对方案 | |
| 32 | + | ||
| 33 | + | **针对穿透(key 对应的数据不存在)** | |
| 34 | + | - 缓存空值:查不到也把空结果缓存起来(设置较短过期时间),避免相同的无效 key 反复回源。 | |
| 35 | + | - 布隆过滤器:在缓存之前加一层布隆过滤器,快速判断 key 是否“可能存在”,不存在的直接拦掉。 | |
| 36 | + | - 接口层校验:对明显非法的 key(格式、范围)提前拦截,防止被恶意构造。 | |
| 37 | + | ||
| 38 | + | **针对击穿(单个热点 key 失效瞬间的并发回源)** | |
| 39 | + | - 互斥锁 / 单飞(singleflight):只放一个请求去回源重建缓存,其余请求等待或短暂重试。 | |
| 40 | + | - 逻辑过期:缓存不设物理过期,存一个逻辑过期时间,过期后由后台异步重建,读请求始终拿到旧值不阻塞。 | |
| 41 | + | - 热点 key 预热与永不过期:对确定的热点数据提前加载并单独维护刷新。 | |
| 42 | + | ||
| 43 | + | **针对雪崩(大量 key 同时失效 / 缓存整体不可用)** | |
| 44 | + | - 过期时间打散:在基础过期时间上加随机抖动,避免大量 key 同一时刻集中失效。 | |
| 45 | + | - 多级缓存:本地缓存 + 分布式缓存,降低单层失效带来的冲击。 | |
| 46 | + | - 高可用与限流降级:Redis 集群 / 主从保证可用;DB 前加限流、熔断、降级,避免被瞬时流量打垮。 | |
| 47 | + | ||
| 48 | + | ### 小结 | |
| 49 | + | ||
| 50 | + | 抓住“查询缓存的 key 不存在”这个共性,再区分**数据源里到底有没有**以及**是单点还是大面积**,三种场景和对应方案就能自然对上号,不必去死记名字。 | |
| 51 | + | ||
| 52 | + | --- | |
| 53 | + | ||
| 54 | + | > 注:本文档原始仓库在一次数据迁移中丢失,仅数据库预览保留了开头至“查询缓存的key不存在”一段(原文)。此分割线以上、该句之后的内容为根据原文主题与结构重建补全,供参考,可自行订正。 | |