【从零开始学习Redis|第四篇】从底层理解缓存问题:雪崩、击穿、穿透与一致性设计

真正理解雪崩、击穿、穿透的方法只有一个:

理解缓存系统的运行规律

一、为什么需要缓存?

想象你做了一个简单的博客网站。

用户访问文章时,服务器会做这件事:

查询数据库 → 返回数据

如果有 10000 个用户同时访问:

数据库就会变成这样:

大量查询请求 → 数据库 CPU 爆满

数据库是整个系统最贵、最慢的部分。

所以工程师会加一层东西:

缓存

系统结构变成:

用户

服务器

缓存(Redis)

数据库(MySQL)

访问流程是:

1 先查缓存

2 缓存没有再查数据库

3 查到数据后写入缓存

这样大部分请求都会停在缓存层。

数据库压力就会小很多。

二、缓存系统的一个核心特点

缓存不是完整数据

因为缓存通常:

1 有过期时间

2 内存容量有限

所以缓存一定会出现:

有些数据存在 有些数据不存在

正是这个特点,导致了后面三个经典问题:

缓存穿透 缓存击穿 缓存雪崩

它们本质上都是:

缓存没有挡住请求,导致请求直接冲击数据库

只是发生的方式不同。

三、什么是缓存穿透?

想象一个请求:

java 复制代码
/article/999999

但数据库里根本没有这篇文章。

流程会变成:

Redis:没有 MySQL:没有

如果用户不断访问这个不存在的数据:

请求

Redis(没有)

MySQL(没有)

每次都会查询数据库。

这就叫:

缓存穿透

本质是:

查询不存在的数据 缓存无法拦截

穿透为什么危险?

如果有人恶意攻击:

每秒10万请求 访问不存在的ID

那么:

所有请求都会打到数据库 数据库就会崩溃。

如何解决缓存穿透?

1. 缓存空值

当数据库发现数据不存在时:

也写入缓存。

例如:

key: article:999999 value: null

设置短过期时间:5分钟

这样下次访问时:

Redis直接返回null

数据库就不会再被访问。
2. 布隆过滤器

在系统入口建立一个:

布隆过滤器

它的作用是:

快速判断某个ID是否可能存在

如果判断:

一定不存在

就直接拒绝请求。

数据库完全不会被访问。

四、什么是缓存击穿?

缓存击穿发生在:

热点数据

比如一篇特别火的文章:

article:1001

每天可能有:几万次访问

某一刻:

缓存刚好过期。

article:1001 缓存失效

突然:5000个用户同时访问

所有请求都会:

同时查询数据库 数据库瞬间压力暴涨

这就是:

缓存击穿

本质是:

热点数据缓存失效

大量请求同时访问数据库

如何解决缓存击穿?

最常见的方法是:

互斥锁

意思是:

当缓存失效时:

只允许一个线程查询数据库。

流程:

1 第一个请求获得锁

2 查询数据库

3 写入缓存

4 释放锁

其他请求:

等待缓存恢复

这样数据库只会被查询一次。

五、什么是缓存雪崩?

缓存雪崩发生在:

大量缓存同时过期

比如系统中有:

100万个缓存key

如果这些缓存设置了:

同样的过期时间

例如:1小时

那么一小时后:

所有缓存一起失效

此时所有请求都会:

直接访问数据库 数据库瞬间崩溃。

这就是:

缓存雪崩

本质是:

缓存集体失效

数据库压力瞬间爆炸

如何解决缓存雪崩?

  • 方法一:随机过期时间

不要让缓存同时过期。

例如:

3600 + random(300)

意思是:

1小时 + 随机5分钟

这样缓存过期时间就会分散。

  • 方法二:多级缓存

增加缓存层:

本地缓存

Redis缓存

数据库

系统变成:

用户

本地缓存

Redis

MySQL

这样压力会被多层分散。

六、数据库和缓存如何保持一致?

这是缓存系统里最难的问题。

因为系统有两个数据源:

数据库 缓存

如果更新顺序不对,就会出现:

数据不一致

例如:

数据库更新了,但缓存还是旧数据。

常见错误做法

错误流程:

更新数据库

更新缓存

如果更新缓存失败:

数据库新数据

缓存旧数据

就出现不一致。

最常见解决方案:先更新数据库,再删除缓存

工程上最常见的方式是:

更新数据库

删除缓存

流程:

update MySQL

delete Redis

为什么要删除而不是更新?

因为:

缓存可以重新生成

当下次请求到来时:

缓存不存在

→ 查询数据库

→ 重新写缓存

数据自然就一致了。

七、完整流程总结

读取数据:

查Redis

存在 → 返回

不存在

查MySQL

写入Redis

返回

更新数据:

更新MySQL

删除Redis

八、理解缓存系统的核心本质

如果把所有技术细节都抽象掉,缓存系统的本质其实只有一句话:

缓存是用内存空间换取访问时间的一种系统设计。

而缓存问题(雪崩、击穿、穿透)本质都是:

缓存没有成功拦截请求

导致:

请求直接冲击数据库

所以缓存设计的核心目标是:

1 尽量让请求停在缓存层

2 防止请求洪水冲向数据库

3 保证数据最终一致

相关推荐
likerhood12 小时前
Java 中的 `clone()` 与 `Cloneable` 接口详解
java·开发语言·python
DavidSoCool12 小时前
Springboot AI 创建MCP Server
java·spring·ai·大模型·springboot·mcp
前端技术12 小时前
华为余承东:鸿蒙终端设备数突破5500万
java·前端·javascript·人工智能·python·华为·harmonyos
notfound404312 小时前
解决SpringCloudGateway用户请求超时导致日志未记录情况
java·spring boot·spring·gateway·springcloud
Adellle12 小时前
Java 异步回调
java·开发语言·多线程
qeen8712 小时前
【算法笔记】差分与经典例题解析
c语言·c++·笔记·学习·算法·差分
SamDeepThinking12 小时前
如何理解 Spring 当中的 Bean?
java·后端·面试
pupudawang12 小时前
docker desktop安装redis
redis·docker·容器
MY_TEUCK12 小时前
【MY_TRUCK中间件实战】Redis 入门教程:从基础命令到 Spring Boot 实战
spring boot·redis·中间件
敖正炀12 小时前
阻塞队列-0-3-最佳实践
java