文章目录
- 前言
- 一、三大缓存问题的核心区别
- 二、缓存穿透
-
- 2.1 什么是缓存穿透?
- 2.2 缓存穿透的业务流程图
- 2.3 典型场景
- 2.4 危害分析
- 2.5 解决方案
-
- 方案一:布隆过滤器
- 方案二:缓存空对象
- 方案三:两种方案结合
- 三、缓存击穿
-
- 3.1 什么是缓存击穿?
- 3.2 缓存击穿问题示意图
- 3.3 典型场景
- 3.4 危害分析
- 3.5 解决方案
-
- 方案一:互斥锁
- 方案二:逻辑过期
- 方案三:热点Key永不过期
- 四、缓存雪崩
-
- 4.1 什么是缓存雪崩?
- 4.2 缓存雪崩问题示意图
- 4.3 触发场景
-
- 场景一:大量Key同时过期
- 场景二:Redis集群故障
- 4.4 危害分析
- 4.5 解决方案
-
- 方案一:过期时间随机化
- 方案二:多级缓存
- 方案三:Redis高可用架构
- 方案四:限流降级
- 五、三种问题的对比总结
- 六、生产环境最佳实践
-
- 6.1 分层防御策略
- 6.2 监控与告警
- 6.3 压测与演练
- 七、总结
前言
在高并发系统设计中,缓存是抵挡数据库洪峰的第一道防线。然而,这道防线并非固若金汤——缓存雪崩、缓存穿透、缓存击穿作为三大经典缓存问题,几乎是每一位后端工程师在实际生产中都可能遇到的"梦魇"。它们名字相似,但成因、表现和解决方案却截然不同。
一、三大缓存问题的核心区别
在深入细节之前,我们先通过一张对比表格快速建立整体认知:
| 缓存穿透 | 数据不存在 | 查询根本不存在的数据 | 绕过缓存直击DB | 缓存和DB都没有 |
| 缓存击穿 | 热点Key过期 | 某个热点Key刚好过期 | 瞬间大并发打崩DB | 单个Key过期,并发极高 |
| 缓存雪崩 | 大规模失效 | 大量Key同时过期或Redis宕机 | 整体流量冲击DB | 批量Key失效,范围大 |
二、缓存穿透
2.1 什么是缓存穿透?
缓存穿透是指查询一个根本不存在的数据。由于缓存中不存在,请求会直接穿透到数据库;又因为数据库中也不存在,所以无法回写缓存。这就导致每次请求这种不存在的数据时,都会直击数据库。
2.2 缓存穿透的业务流程图
下面这张图清晰地展示了缓存穿透的发生机制——当请求的数据在缓存和数据库中都不存在时,每次请求都会直接访问数据库,缓存形同虚设。
#mermaid-svg-zrvjp5Lb5r74UtOB{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zrvjp5Lb5r74UtOB .error-icon{fill:#552222;}#mermaid-svg-zrvjp5Lb5r74UtOB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zrvjp5Lb5r74UtOB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zrvjp5Lb5r74UtOB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zrvjp5Lb5r74UtOB .marker.cross{stroke:#333333;}#mermaid-svg-zrvjp5Lb5r74UtOB svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zrvjp5Lb5r74UtOB p{margin:0;}#mermaid-svg-zrvjp5Lb5r74UtOB .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-zrvjp5Lb5r74UtOB .cluster-label text{fill:#333;}#mermaid-svg-zrvjp5Lb5r74UtOB .cluster-label span{color:#333;}#mermaid-svg-zrvjp5Lb5r74UtOB .cluster-label span p{background-color:transparent;}#mermaid-svg-zrvjp5Lb5r74UtOB .label text,#mermaid-svg-zrvjp5Lb5r74UtOB span{fill:#333;color:#333;}#mermaid-svg-zrvjp5Lb5r74UtOB .node rect,#mermaid-svg-zrvjp5Lb5r74UtOB .node circle,#mermaid-svg-zrvjp5Lb5r74UtOB .node ellipse,#mermaid-svg-zrvjp5Lb5r74UtOB .node polygon,#mermaid-svg-zrvjp5Lb5r74UtOB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zrvjp5Lb5r74UtOB .rough-node .label text,#mermaid-svg-zrvjp5Lb5r74UtOB .node .label text,#mermaid-svg-zrvjp5Lb5r74UtOB .image-shape .label,#mermaid-svg-zrvjp5Lb5r74UtOB .icon-shape .label{text-anchor:middle;}#mermaid-svg-zrvjp5Lb5r74UtOB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zrvjp5Lb5r74UtOB .rough-node .label,#mermaid-svg-zrvjp5Lb5r74UtOB .node .label,#mermaid-svg-zrvjp5Lb5r74UtOB .image-shape .label,#mermaid-svg-zrvjp5Lb5r74UtOB .icon-shape .label{text-align:center;}#mermaid-svg-zrvjp5Lb5r74UtOB .node.clickable{cursor:pointer;}#mermaid-svg-zrvjp5Lb5r74UtOB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zrvjp5Lb5r74UtOB .arrowheadPath{fill:#333333;}#mermaid-svg-zrvjp5Lb5r74UtOB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zrvjp5Lb5r74UtOB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zrvjp5Lb5r74UtOB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zrvjp5Lb5r74UtOB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zrvjp5Lb5r74UtOB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zrvjp5Lb5r74UtOB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zrvjp5Lb5r74UtOB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zrvjp5Lb5r74UtOB .cluster text{fill:#333;}#mermaid-svg-zrvjp5Lb5r74UtOB .cluster span{color:#333;}#mermaid-svg-zrvjp5Lb5r74UtOB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zrvjp5Lb5r74UtOB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zrvjp5Lb5r74UtOB rect.text{fill:none;stroke-width:0;}#mermaid-svg-zrvjp5Lb5r74UtOB .icon-shape,#mermaid-svg-zrvjp5Lb5r74UtOB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zrvjp5Lb5r74UtOB .icon-shape p,#mermaid-svg-zrvjp5Lb5r74UtOB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zrvjp5Lb5r74UtOB .icon-shape rect,#mermaid-svg-zrvjp5Lb5r74UtOB .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zrvjp5Lb5r74UtOB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zrvjp5Lb5r74UtOB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zrvjp5Lb5r74UtOB :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
命中
未命中
存在
不存在
用户请求
查询缓存
返回数据
查询数据库
数据是否存在
返回数据
返回空值
2.3 典型场景
- 恶意攻击:攻击者频繁请求不存在的ID(如-1、9999999等)
- 业务误操作:前端传入不存在的查询条件
- 数据未初始化:新业务上线,历史数据尚未生成
2.4 危害分析
当这种请求量足够大时,数据库会承受大量无效查询,导致:
- 数据库连接数耗尽
- CPU飙升
- 正常业务请求被阻塞
- 严重时引发数据库宕机
2.5 解决方案
方案一:布隆过滤器
原理:使用一个超大的位数组和多个哈希函数,将数据库中所有存在的key映射到位数组中。请求到达时,先通过布隆过滤器判断key是否存在:
- 如果过滤器说不存在,则一定不存在,直接返回
- 如果过滤器说存在,则可能存在(有误判率),继续查询缓存和数据库
布隆过滤器拦截流程:
#mermaid-svg-R1KuF5tGYUtIXRI0{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-R1KuF5tGYUtIXRI0 .error-icon{fill:#552222;}#mermaid-svg-R1KuF5tGYUtIXRI0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-R1KuF5tGYUtIXRI0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .marker.cross{stroke:#333333;}#mermaid-svg-R1KuF5tGYUtIXRI0 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-R1KuF5tGYUtIXRI0 p{margin:0;}#mermaid-svg-R1KuF5tGYUtIXRI0 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .cluster-label text{fill:#333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .cluster-label span{color:#333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .cluster-label span p{background-color:transparent;}#mermaid-svg-R1KuF5tGYUtIXRI0 .label text,#mermaid-svg-R1KuF5tGYUtIXRI0 span{fill:#333;color:#333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .node rect,#mermaid-svg-R1KuF5tGYUtIXRI0 .node circle,#mermaid-svg-R1KuF5tGYUtIXRI0 .node ellipse,#mermaid-svg-R1KuF5tGYUtIXRI0 .node polygon,#mermaid-svg-R1KuF5tGYUtIXRI0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-R1KuF5tGYUtIXRI0 .rough-node .label text,#mermaid-svg-R1KuF5tGYUtIXRI0 .node .label text,#mermaid-svg-R1KuF5tGYUtIXRI0 .image-shape .label,#mermaid-svg-R1KuF5tGYUtIXRI0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-R1KuF5tGYUtIXRI0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-R1KuF5tGYUtIXRI0 .rough-node .label,#mermaid-svg-R1KuF5tGYUtIXRI0 .node .label,#mermaid-svg-R1KuF5tGYUtIXRI0 .image-shape .label,#mermaid-svg-R1KuF5tGYUtIXRI0 .icon-shape .label{text-align:center;}#mermaid-svg-R1KuF5tGYUtIXRI0 .node.clickable{cursor:pointer;}#mermaid-svg-R1KuF5tGYUtIXRI0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .arrowheadPath{fill:#333333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-R1KuF5tGYUtIXRI0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R1KuF5tGYUtIXRI0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-R1KuF5tGYUtIXRI0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R1KuF5tGYUtIXRI0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-R1KuF5tGYUtIXRI0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-R1KuF5tGYUtIXRI0 .cluster text{fill:#333;}#mermaid-svg-R1KuF5tGYUtIXRI0 .cluster span{color:#333;}#mermaid-svg-R1KuF5tGYUtIXRI0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-R1KuF5tGYUtIXRI0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-R1KuF5tGYUtIXRI0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-R1KuF5tGYUtIXRI0 .icon-shape,#mermaid-svg-R1KuF5tGYUtIXRI0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R1KuF5tGYUtIXRI0 .icon-shape p,#mermaid-svg-R1KuF5tGYUtIXRI0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-R1KuF5tGYUtIXRI0 .icon-shape rect,#mermaid-svg-R1KuF5tGYUtIXRI0 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R1KuF5tGYUtIXRI0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-R1KuF5tGYUtIXRI0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-R1KuF5tGYUtIXRI0 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
不存在
存在
命中
未命中
用户请求
布隆过滤器
直接返回
查询缓存
返回数据
查询数据库
返回结果
核心优势:
- 内存占用极小:1000万数据仅需约12MB
- 性能极高:时间复杂度O(k),k为哈希函数个数
局限性:
- 存在误判率(可通过参数控制在1%以内)
- 不支持删除操作(可考虑计数布隆过滤器)
- 需要提前加载所有存在的key
方案二:缓存空对象
原理:当查询数据库发现不存在时,仍然将这个"空结果"写入缓存,但设置较短的过期时间(如30-60秒)。
核心优势:
- 实现简单,逻辑直观
- 适用于数据变化不频繁的场景
局限性:
- 会占用额外的缓存空间(可通过短过期时间缓解)
- 可能导致短暂的数据不一致
方案三:两种方案结合
在实际生产中,通常采用布隆过滤器 + 缓存空对象双重保障:
- 布隆过滤器:高效拦截恶意攻击和遍历请求
- 缓存空对象:兜底处理偶发性不存在的数据
三、缓存击穿
3.1 什么是缓存击穿?
缓存击穿是指一个热点key在某个时间点恰好过期,而此时有大量并发请求访问这个key。由于缓存失效,这些请求会同时穿透到数据库,瞬间给数据库带来巨大压力。
3.2 缓存击穿问题示意图
#mermaid-svg-32UdUCcPaM0ClIMQ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-32UdUCcPaM0ClIMQ .error-icon{fill:#552222;}#mermaid-svg-32UdUCcPaM0ClIMQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-32UdUCcPaM0ClIMQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-32UdUCcPaM0ClIMQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-32UdUCcPaM0ClIMQ .marker.cross{stroke:#333333;}#mermaid-svg-32UdUCcPaM0ClIMQ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-32UdUCcPaM0ClIMQ p{margin:0;}#mermaid-svg-32UdUCcPaM0ClIMQ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-32UdUCcPaM0ClIMQ .cluster-label text{fill:#333;}#mermaid-svg-32UdUCcPaM0ClIMQ .cluster-label span{color:#333;}#mermaid-svg-32UdUCcPaM0ClIMQ .cluster-label span p{background-color:transparent;}#mermaid-svg-32UdUCcPaM0ClIMQ .label text,#mermaid-svg-32UdUCcPaM0ClIMQ span{fill:#333;color:#333;}#mermaid-svg-32UdUCcPaM0ClIMQ .node rect,#mermaid-svg-32UdUCcPaM0ClIMQ .node circle,#mermaid-svg-32UdUCcPaM0ClIMQ .node ellipse,#mermaid-svg-32UdUCcPaM0ClIMQ .node polygon,#mermaid-svg-32UdUCcPaM0ClIMQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-32UdUCcPaM0ClIMQ .rough-node .label text,#mermaid-svg-32UdUCcPaM0ClIMQ .node .label text,#mermaid-svg-32UdUCcPaM0ClIMQ .image-shape .label,#mermaid-svg-32UdUCcPaM0ClIMQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-32UdUCcPaM0ClIMQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-32UdUCcPaM0ClIMQ .rough-node .label,#mermaid-svg-32UdUCcPaM0ClIMQ .node .label,#mermaid-svg-32UdUCcPaM0ClIMQ .image-shape .label,#mermaid-svg-32UdUCcPaM0ClIMQ .icon-shape .label{text-align:center;}#mermaid-svg-32UdUCcPaM0ClIMQ .node.clickable{cursor:pointer;}#mermaid-svg-32UdUCcPaM0ClIMQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-32UdUCcPaM0ClIMQ .arrowheadPath{fill:#333333;}#mermaid-svg-32UdUCcPaM0ClIMQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-32UdUCcPaM0ClIMQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-32UdUCcPaM0ClIMQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-32UdUCcPaM0ClIMQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-32UdUCcPaM0ClIMQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-32UdUCcPaM0ClIMQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-32UdUCcPaM0ClIMQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-32UdUCcPaM0ClIMQ .cluster text{fill:#333;}#mermaid-svg-32UdUCcPaM0ClIMQ .cluster span{color:#333;}#mermaid-svg-32UdUCcPaM0ClIMQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-32UdUCcPaM0ClIMQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-32UdUCcPaM0ClIMQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-32UdUCcPaM0ClIMQ .icon-shape,#mermaid-svg-32UdUCcPaM0ClIMQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-32UdUCcPaM0ClIMQ .icon-shape p,#mermaid-svg-32UdUCcPaM0ClIMQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-32UdUCcPaM0ClIMQ .icon-shape rect,#mermaid-svg-32UdUCcPaM0ClIMQ .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-32UdUCcPaM0ClIMQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-32UdUCcPaM0ClIMQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-32UdUCcPaM0ClIMQ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
击穿瞬间
未命中
未命中
未命中
未命中
未命中
时间点t0
热点Key刚好过期
请求1
请求2
请求3
请求4
请求N…
查询缓存
查询缓存
查询缓存
查询缓存
查询缓存
数据库
数据库瞬间压力暴增连接耗尽、响应超时
正常情况
热点Key存在
请求1命中缓存
请求2命中缓存
请求3命中缓存
返回数据
3.3 典型场景
- 首页Banner:首页轮播图配置在凌晨0点过期,零点后大量用户访问
- 热门商品:秒杀商品详情页,商品信息缓存过期
- 微博热搜:某个热搜话题突然爆火,对应缓存恰好过期
3.4 危害分析
击穿的特点是"单点高并发"——针对的是单个Key,但这个Key是热点,并发量极高。如果处理不当,可能导致:
- 数据库瞬间QPS飙升
- 连接池被打满
- 响应时间急剧上升
- 服务不可用
3.5 解决方案
方案一:互斥锁
原理:当缓存失效时,不是所有请求都去查询数据库,而是只让一个请求去查询并重建缓存,其他请求等待或重试。
互斥锁解决方案流程图
#mermaid-svg-odwrwVHfHRvcv5hV{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-odwrwVHfHRvcv5hV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-odwrwVHfHRvcv5hV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-odwrwVHfHRvcv5hV .error-icon{fill:#552222;}#mermaid-svg-odwrwVHfHRvcv5hV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-odwrwVHfHRvcv5hV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-odwrwVHfHRvcv5hV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-odwrwVHfHRvcv5hV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-odwrwVHfHRvcv5hV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-odwrwVHfHRvcv5hV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-odwrwVHfHRvcv5hV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-odwrwVHfHRvcv5hV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-odwrwVHfHRvcv5hV .marker.cross{stroke:#333333;}#mermaid-svg-odwrwVHfHRvcv5hV svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-odwrwVHfHRvcv5hV p{margin:0;}#mermaid-svg-odwrwVHfHRvcv5hV .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-odwrwVHfHRvcv5hV .cluster-label text{fill:#333;}#mermaid-svg-odwrwVHfHRvcv5hV .cluster-label span{color:#333;}#mermaid-svg-odwrwVHfHRvcv5hV .cluster-label span p{background-color:transparent;}#mermaid-svg-odwrwVHfHRvcv5hV .label text,#mermaid-svg-odwrwVHfHRvcv5hV span{fill:#333;color:#333;}#mermaid-svg-odwrwVHfHRvcv5hV .node rect,#mermaid-svg-odwrwVHfHRvcv5hV .node circle,#mermaid-svg-odwrwVHfHRvcv5hV .node ellipse,#mermaid-svg-odwrwVHfHRvcv5hV .node polygon,#mermaid-svg-odwrwVHfHRvcv5hV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-odwrwVHfHRvcv5hV .rough-node .label text,#mermaid-svg-odwrwVHfHRvcv5hV .node .label text,#mermaid-svg-odwrwVHfHRvcv5hV .image-shape .label,#mermaid-svg-odwrwVHfHRvcv5hV .icon-shape .label{text-anchor:middle;}#mermaid-svg-odwrwVHfHRvcv5hV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-odwrwVHfHRvcv5hV .rough-node .label,#mermaid-svg-odwrwVHfHRvcv5hV .node .label,#mermaid-svg-odwrwVHfHRvcv5hV .image-shape .label,#mermaid-svg-odwrwVHfHRvcv5hV .icon-shape .label{text-align:center;}#mermaid-svg-odwrwVHfHRvcv5hV .node.clickable{cursor:pointer;}#mermaid-svg-odwrwVHfHRvcv5hV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-odwrwVHfHRvcv5hV .arrowheadPath{fill:#333333;}#mermaid-svg-odwrwVHfHRvcv5hV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-odwrwVHfHRvcv5hV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-odwrwVHfHRvcv5hV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-odwrwVHfHRvcv5hV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-odwrwVHfHRvcv5hV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-odwrwVHfHRvcv5hV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-odwrwVHfHRvcv5hV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-odwrwVHfHRvcv5hV .cluster text{fill:#333;}#mermaid-svg-odwrwVHfHRvcv5hV .cluster span{color:#333;}#mermaid-svg-odwrwVHfHRvcv5hV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-odwrwVHfHRvcv5hV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-odwrwVHfHRvcv5hV rect.text{fill:none;stroke-width:0;}#mermaid-svg-odwrwVHfHRvcv5hV .icon-shape,#mermaid-svg-odwrwVHfHRvcv5hV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-odwrwVHfHRvcv5hV .icon-shape p,#mermaid-svg-odwrwVHfHRvcv5hV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-odwrwVHfHRvcv5hV .icon-shape rect,#mermaid-svg-odwrwVHfHRvcv5hV .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-odwrwVHfHRvcv5hV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-odwrwVHfHRvcv5hV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-odwrwVHfHRvcv5hV :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
命中
未命中
成功
失败
用户请求
查询缓存
返回数据
尝试获取锁
查询数据库
重建缓存
释放锁
返回数据
等待后重试
核心流程:
核心优势:
- 保证只有一个请求查询数据库
- 实现相对简单
局限性:
- 引入锁竞争,降低系统吞吐量
- 需设置合理锁超时,避免死锁
- 可能造成线程阻塞
方案二:逻辑过期
原理:缓存中不设置物理过期时间,而是存储一个"逻辑过期时间"。当查询发现逻辑过期时,启动一个独立线程去更新缓存,当前请求返回旧数据。
核心流程:
核心优势:
- 读操作无阻塞,性能极高
- 适合"最终一致性"可接受的场景
局限性:
- 实现复杂度较高
- 数据短暂不一致(旧数据可能被返回)
方案三:热点Key永不过期
原理:对于明确的热点Key,不设置物理过期时间,而是通过后台定时任务主动更新。
适用场景:业务可预知的热点(如首页配置、爆款商品)
核心优势:
- 彻底消除击穿风险
- 实现简单
局限性:
- 只能用于可预知的热点
- 需要额外的定时任务维护
四、缓存雪崩
4.1 什么是缓存雪崩?
缓存雪崩是指由于大量缓存key同时过期或Redis节点宕机,导致所有请求直接落到数据库上,数据库瞬间压力过大甚至崩溃的现象。
4.2 缓存雪崩问题示意图
#mermaid-svg-YbRUji9zX655m49F{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YbRUji9zX655m49F .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YbRUji9zX655m49F .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YbRUji9zX655m49F .error-icon{fill:#552222;}#mermaid-svg-YbRUji9zX655m49F .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YbRUji9zX655m49F .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YbRUji9zX655m49F .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YbRUji9zX655m49F .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YbRUji9zX655m49F .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YbRUji9zX655m49F .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YbRUji9zX655m49F .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YbRUji9zX655m49F .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YbRUji9zX655m49F .marker.cross{stroke:#333333;}#mermaid-svg-YbRUji9zX655m49F svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YbRUji9zX655m49F p{margin:0;}#mermaid-svg-YbRUji9zX655m49F .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-YbRUji9zX655m49F .cluster-label text{fill:#333;}#mermaid-svg-YbRUji9zX655m49F .cluster-label span{color:#333;}#mermaid-svg-YbRUji9zX655m49F .cluster-label span p{background-color:transparent;}#mermaid-svg-YbRUji9zX655m49F .label text,#mermaid-svg-YbRUji9zX655m49F span{fill:#333;color:#333;}#mermaid-svg-YbRUji9zX655m49F .node rect,#mermaid-svg-YbRUji9zX655m49F .node circle,#mermaid-svg-YbRUji9zX655m49F .node ellipse,#mermaid-svg-YbRUji9zX655m49F .node polygon,#mermaid-svg-YbRUji9zX655m49F .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YbRUji9zX655m49F .rough-node .label text,#mermaid-svg-YbRUji9zX655m49F .node .label text,#mermaid-svg-YbRUji9zX655m49F .image-shape .label,#mermaid-svg-YbRUji9zX655m49F .icon-shape .label{text-anchor:middle;}#mermaid-svg-YbRUji9zX655m49F .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YbRUji9zX655m49F .rough-node .label,#mermaid-svg-YbRUji9zX655m49F .node .label,#mermaid-svg-YbRUji9zX655m49F .image-shape .label,#mermaid-svg-YbRUji9zX655m49F .icon-shape .label{text-align:center;}#mermaid-svg-YbRUji9zX655m49F .node.clickable{cursor:pointer;}#mermaid-svg-YbRUji9zX655m49F .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YbRUji9zX655m49F .arrowheadPath{fill:#333333;}#mermaid-svg-YbRUji9zX655m49F .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YbRUji9zX655m49F .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YbRUji9zX655m49F .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YbRUji9zX655m49F .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YbRUji9zX655m49F .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YbRUji9zX655m49F .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YbRUji9zX655m49F .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YbRUji9zX655m49F .cluster text{fill:#333;}#mermaid-svg-YbRUji9zX655m49F .cluster span{color:#333;}#mermaid-svg-YbRUji9zX655m49F div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YbRUji9zX655m49F .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YbRUji9zX655m49F rect.text{fill:none;stroke-width:0;}#mermaid-svg-YbRUji9zX655m49F .icon-shape,#mermaid-svg-YbRUji9zX655m49F .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YbRUji9zX655m49F .icon-shape p,#mermaid-svg-YbRUji9zX655m49F .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YbRUji9zX655m49F .icon-shape rect,#mermaid-svg-YbRUji9zX655m49F .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YbRUji9zX655m49F .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YbRUji9zX655m49F .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YbRUji9zX655m49F :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
雪崩场景二:Redis集群故障
主节点宕机
网络分区
整体故障
Redis集群
哨兵切换服务短暂不可用
部分节点不可用
Redis完全不可用
所有请求
数据库
数据库直接被击穿
雪崩场景一:大量Key同时过期
时间到达12:00
Key1过期
Key2过期
Key3过期
请求组A
请求组B
请求组C
缓存失效
缓存失效
缓存失效
数据库
数据库瞬间承受数倍于平时的流量
正常缓存分布
Key1 过期时间: 12:00
Key2 过期时间: 12:00
Key3 过期时间: 12:00
Key4 过期时间: 12:05
Key5 过期时间: 12:10
4.3 触发场景
场景一:大量Key同时过期
- 业务初始化时设置了相同的过期时间(如统一凌晨0点过期)
- 定时任务批量更新缓存,导致同一时间点大量失效
场景二:Redis集群故障
- 主节点宕机,哨兵正在切换
- 网络分区导致部分节点不可用
- 集群整体故障
4.4 危害分析
雪崩是三个问题中影响范围最大的:
- 数据库可能承受平时10倍甚至100倍的流量
- 服务响应时间急剧上升
- 可能引发服务链式崩溃
4.5 解决方案
方案一:过期时间随机化
原理:在设置缓存过期时间时,在基础时间上增加一个随机偏移量,避免大量Key同时过期。
实践方法:
- 基础过期时间设为1小时
- 随机增加0-10分钟的偏移
- 使Key的过期时间均匀分布
核心优势:
- 实现最简单,效果显著
- 几乎零成本
方案二:多级缓存
原理:构建多级缓存体系,当一级缓存失效时,二级缓存仍能提供服务。
多级缓存架构图:
#mermaid-svg-CFHLw9rtyZWuJQfM{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CFHLw9rtyZWuJQfM .error-icon{fill:#552222;}#mermaid-svg-CFHLw9rtyZWuJQfM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CFHLw9rtyZWuJQfM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CFHLw9rtyZWuJQfM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CFHLw9rtyZWuJQfM .marker.cross{stroke:#333333;}#mermaid-svg-CFHLw9rtyZWuJQfM svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CFHLw9rtyZWuJQfM p{margin:0;}#mermaid-svg-CFHLw9rtyZWuJQfM .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-CFHLw9rtyZWuJQfM .cluster-label text{fill:#333;}#mermaid-svg-CFHLw9rtyZWuJQfM .cluster-label span{color:#333;}#mermaid-svg-CFHLw9rtyZWuJQfM .cluster-label span p{background-color:transparent;}#mermaid-svg-CFHLw9rtyZWuJQfM .label text,#mermaid-svg-CFHLw9rtyZWuJQfM span{fill:#333;color:#333;}#mermaid-svg-CFHLw9rtyZWuJQfM .node rect,#mermaid-svg-CFHLw9rtyZWuJQfM .node circle,#mermaid-svg-CFHLw9rtyZWuJQfM .node ellipse,#mermaid-svg-CFHLw9rtyZWuJQfM .node polygon,#mermaid-svg-CFHLw9rtyZWuJQfM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CFHLw9rtyZWuJQfM .rough-node .label text,#mermaid-svg-CFHLw9rtyZWuJQfM .node .label text,#mermaid-svg-CFHLw9rtyZWuJQfM .image-shape .label,#mermaid-svg-CFHLw9rtyZWuJQfM .icon-shape .label{text-anchor:middle;}#mermaid-svg-CFHLw9rtyZWuJQfM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CFHLw9rtyZWuJQfM .rough-node .label,#mermaid-svg-CFHLw9rtyZWuJQfM .node .label,#mermaid-svg-CFHLw9rtyZWuJQfM .image-shape .label,#mermaid-svg-CFHLw9rtyZWuJQfM .icon-shape .label{text-align:center;}#mermaid-svg-CFHLw9rtyZWuJQfM .node.clickable{cursor:pointer;}#mermaid-svg-CFHLw9rtyZWuJQfM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CFHLw9rtyZWuJQfM .arrowheadPath{fill:#333333;}#mermaid-svg-CFHLw9rtyZWuJQfM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CFHLw9rtyZWuJQfM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CFHLw9rtyZWuJQfM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CFHLw9rtyZWuJQfM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CFHLw9rtyZWuJQfM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CFHLw9rtyZWuJQfM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CFHLw9rtyZWuJQfM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CFHLw9rtyZWuJQfM .cluster text{fill:#333;}#mermaid-svg-CFHLw9rtyZWuJQfM .cluster span{color:#333;}#mermaid-svg-CFHLw9rtyZWuJQfM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CFHLw9rtyZWuJQfM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CFHLw9rtyZWuJQfM rect.text{fill:none;stroke-width:0;}#mermaid-svg-CFHLw9rtyZWuJQfM .icon-shape,#mermaid-svg-CFHLw9rtyZWuJQfM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CFHLw9rtyZWuJQfM .icon-shape p,#mermaid-svg-CFHLw9rtyZWuJQfM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CFHLw9rtyZWuJQfM .icon-shape rect,#mermaid-svg-CFHLw9rtyZWuJQfM .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CFHLw9rtyZWuJQfM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CFHLw9rtyZWuJQfM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CFHLw9rtyZWuJQfM :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
命中
未命中
命中
未命中
用户请求
L1本地缓存
返回数据
L2分布式缓存
返回数据
查询数据库
更新缓存
返回数据
典型架构:
- L1缓存:本地缓存(Caffeine/Guava),过期时间短
- L2缓存:分布式缓存(Redis),过期时间较长
- L3存储:数据库,最终数据源
核心优势:
- 多层防护,抗冲击能力强
- L1缓存可拦截大量重复请求
局限性:
- 实现复杂度高
- 需处理多级缓存一致性问题
方案三:Redis高可用架构
原理:通过部署Redis集群、主从复制、哨兵模式等,避免单点故障导致的服务不可用。
Redis哨兵模式高可用架构图:
#mermaid-svg-m8GtUiWBLEY5MSU7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-m8GtUiWBLEY5MSU7 .error-icon{fill:#552222;}#mermaid-svg-m8GtUiWBLEY5MSU7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-m8GtUiWBLEY5MSU7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .marker.cross{stroke:#333333;}#mermaid-svg-m8GtUiWBLEY5MSU7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-m8GtUiWBLEY5MSU7 p{margin:0;}#mermaid-svg-m8GtUiWBLEY5MSU7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .cluster-label text{fill:#333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .cluster-label span{color:#333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .cluster-label span p{background-color:transparent;}#mermaid-svg-m8GtUiWBLEY5MSU7 .label text,#mermaid-svg-m8GtUiWBLEY5MSU7 span{fill:#333;color:#333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .node rect,#mermaid-svg-m8GtUiWBLEY5MSU7 .node circle,#mermaid-svg-m8GtUiWBLEY5MSU7 .node ellipse,#mermaid-svg-m8GtUiWBLEY5MSU7 .node polygon,#mermaid-svg-m8GtUiWBLEY5MSU7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-m8GtUiWBLEY5MSU7 .rough-node .label text,#mermaid-svg-m8GtUiWBLEY5MSU7 .node .label text,#mermaid-svg-m8GtUiWBLEY5MSU7 .image-shape .label,#mermaid-svg-m8GtUiWBLEY5MSU7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-m8GtUiWBLEY5MSU7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-m8GtUiWBLEY5MSU7 .rough-node .label,#mermaid-svg-m8GtUiWBLEY5MSU7 .node .label,#mermaid-svg-m8GtUiWBLEY5MSU7 .image-shape .label,#mermaid-svg-m8GtUiWBLEY5MSU7 .icon-shape .label{text-align:center;}#mermaid-svg-m8GtUiWBLEY5MSU7 .node.clickable{cursor:pointer;}#mermaid-svg-m8GtUiWBLEY5MSU7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .arrowheadPath{fill:#333333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-m8GtUiWBLEY5MSU7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8GtUiWBLEY5MSU7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-m8GtUiWBLEY5MSU7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8GtUiWBLEY5MSU7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-m8GtUiWBLEY5MSU7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-m8GtUiWBLEY5MSU7 .cluster text{fill:#333;}#mermaid-svg-m8GtUiWBLEY5MSU7 .cluster span{color:#333;}#mermaid-svg-m8GtUiWBLEY5MSU7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-m8GtUiWBLEY5MSU7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-m8GtUiWBLEY5MSU7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-m8GtUiWBLEY5MSU7 .icon-shape,#mermaid-svg-m8GtUiWBLEY5MSU7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8GtUiWBLEY5MSU7 .icon-shape p,#mermaid-svg-m8GtUiWBLEY5MSU7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-m8GtUiWBLEY5MSU7 .icon-shape rect,#mermaid-svg-m8GtUiWBLEY5MSU7 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8GtUiWBLEY5MSU7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-m8GtUiWBLEY5MSU7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-m8GtUiWBLEY5MSU7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
哨兵集群
Sentinel 1
Sentinel 2
Sentinel 3
客户端
Redis主节点
Redis从节点1
Redis从节点2
架构选择:
- 主从+哨兵:自动故障转移,保障服务连续性
- Redis Cluster:数据分片,水平扩展
- 多机房部署:跨机房容灾
核心优势:
- 从根源上避免因Redis宕机导致的雪崩
- 提升整体系统可用性
方案四:限流降级
原理:当数据库压力过大时,主动丢弃部分请求,保证核心业务可用。
常用策略:
- 限流:限制每秒请求数(令牌桶/滑动窗口)
- 降级:非核心业务返回默认值或缓存旧数据
- 熔断:当错误率达到阈值时,快速失败
核心优势:
- 保护数据库不被击垮
- 保证系统整体可用性
五、三种问题的对比总结
| 问题根源 | 数据不存在 | 单个热点Key过期 | 大量Key同时过期/Redis宕机 |
| 影响范围 | 单个Key(但可无限次请求) | 单个热点Key | 整体缓存服务 |
| 并发特征 | 可高可低 | 瞬间超高并发 | 整体流量冲击 |
| 首要解决方案 | 布隆过滤器 | 互斥锁 | 过期时间随机化 |
| 辅助方案 | 缓存空对象 | 逻辑过期 | 多级缓存 |
| 兜底方案 | 限流降级 | 热点Key永不过期 | 高可用集群 |
六、生产环境最佳实践
6.1 分层防御策略
在实际生产环境中,应该采用分层防御的策略:
| 入口层 | 布隆过滤器 | 拦截穿透请求 |
| 缓存层 | 过期时间随机化、多级缓存 | 预防雪崩 |
| 热点层 | 互斥锁、逻辑过期 | 处理击穿 |
| 数据库层 | 限流、熔断、降级 | 终极保护 |
6.2 监控与告警
建立完善的监控体系,及时发现异常:
- 缓存命中率:突然下降可能预示问题
- 数据库QPS:异常飙升需立即告警
- Redis内存/连接数:资源瓶颈预警
- 慢查询日志:发现异常访问模式
6.3 压测与演练
定期进行压力测试和故障演练:
- 模拟缓存穿透攻击
- 模拟热点Key失效场景
- 模拟Redis节点宕机
- 验证限流降级策略有效性
七、总结
缓存雪崩、缓存穿透、缓存击穿是高并发系统设计中必须面对的三大挑战。它们看似相似,但成因和解决方案各不相同:
| 缓存穿透 | 查询不存在的数据 | 布隆过滤器前置拦截 |
| 缓存击穿 | 单个热点Key过期 | 互斥锁或逻辑过期 |
| 缓存雪崩 | 大量Key同时失效 | 过期时间随机化 + 高可用集群 |
在实际生产环境中,这三大问题往往同时存在或相互诱发。最佳实践是组合使用多种方案,构建多层次的防御体系,同时配合完善的监控和限流降级机制,才能确保缓存系统的稳定可靠。


