缓存三大问题及其解决方案

news/2025/2/21 22:57:27/

缓存三大问题及其解决方案

1. 前言

​ 在现代系统架构中,缓存与数据库的结合使用是一种经典的设计模式。为了确保缓存中的数据与数据库中的数据保持一致,通常会给缓存数据设置一个过期时间。当系统接收到用户请求时,首先会访问缓存。如果缓存中不存在所需数据,系统会进一步查询数据库,并将获取到的数据回写到缓存中。这样,当系统再次接收到相同的请求时,便可以直接从缓存中获取数据并返回给用户,从而提升系统的响应速度和性能。

缓存与数据库交互示意图

2. 缓存穿透

​ 在上述系统架构中,当用户从缓存中获取数据时,如果缓存中不存在该数据,系统会转而查询数据库。然而,如果数据库中也不存在该数据,系统将无法将数据回写到缓存中。这导致后续相同的请求仍然会直接访问数据库。如果短时间内系统接收到大量此类请求,数据库的压力将急剧增加,甚至可能导致数据库服务器宕机。

缓存穿透示意图

2.1 解决方案
  1. 限制非法请求

    ​ 缓存穿透问题往往是由于恶意攻击(如黑客攻击)导致的。因此,我们可以在API入口处对请求的合法性进行检测。例如,可以检查请求的IP地址、参数和字段的合法性。如果请求被判定为非法,系统可以直接返回错误响应,而无需进一步访问缓存或数据库。

  2. 缓存空值或默认值

    ​ 当请求的数据在缓存和数据库中均不存在时,系统可以将该数据的键值对缓存起来,并将其值设置为空或赋予一个默认值。这样,当系统再次接收到相同的请求时,便可以直接从缓存中获取数据并返回,从而避免了对数据库的重复查询。

  3. 使用布隆过滤器

    ​ 布隆过滤器是一种高效的数据结构,用于判断某个元素是否存在于集合中。我们可以在写入数据库数据时,同步将该数据的标识存入布隆过滤器中。当系统接收到用户请求时,如果缓存中不存在该数据,系统可以先查询布隆过滤器。如果布隆过滤器中也不存在该数据,系统可以直接返回,而无需访问数据库。这种方法能够有效减少数据库的查询压力,尤其是在面对大量请求时。

3. 缓存雪崩

​ 通常情况下,缓存中的数据会设置一个过期时间,以便及时更新数据,确保与数据库中的数据保持一致。然而,如果大量缓存在同一时间过期,系统将无法从缓存中获取数据,导致大量请求直接涌入数据库。这种情况下,数据库的压力将急剧增加,甚至可能导致数据库崩溃。

缓存雪崩示意图

3.1 解决方案
  1. 均匀设置过期时间

    ​ 为了避免大量缓存在同一时间过期,可以为缓存数据设置随机的过期时间。通过均匀分布缓存的过期时间,可以有效避免缓存同时失效,从而减轻数据库的压力。

  2. 使用互斥锁

    ​ 当系统接收到用户请求时,如果请求的数据不在缓存中,系统可以为该请求加一个互斥锁,确保同一时间内只有一个请求能够访问数据库。当数据库中的数据被成功查询并回写到缓存后,系统再释放该锁。其他请求在缓存中获取不到数据时,可以选择等待锁释放或直接返回空值或默认值。

    ​ 需要注意的是,互斥锁应设置一个合理的过期时间,以防止因异常情况导致锁无法释放。

  3. 后台线程更新缓存

    ​ 当系统接收到用户请求时,如果请求的数据不在缓存中,系统可以调用后台线程或通过消息队列触发后台线程来更新缓存。后台线程会首先检查缓存中是否存在该数据,如果存在则不执行更新操作;如果不存在,则从数据库中获取数据并回写到缓存中。

    ​ 在系统刚上线时,可以通过手动调用后台线程,将部分热点数据预先加载到缓存中,以避免冷启动时的大量数据库查询。

4. 缓存击穿

​ 在秒杀等高频访问场景中,某些热点数据会被频繁访问。如果这些热点数据恰好过期,大量请求将无法从缓存中获取数据,转而直接访问数据库。这种情况下,数据库的压力将急剧增加,甚至可能导致数据库崩溃。

缓存击穿示意图

4.1 解决方案

​ 缓存击穿可以视为缓存雪崩的一种特殊情况,因此其解决方案与缓存雪崩类似。

  1. 使用互斥锁

    ​ 当系统在缓存中无法获取到数据时,可以为该请求加一个互斥锁,并设置合理的过期时间。这样可以确保同一时间内只有一个请求能够访问数据库,从而避免大量请求同时涌入数据库。

  2. 后台线程更新缓存

    ​ 当系统在缓存中无法获取到数据时,可以调用后台线程来更新缓存。后台线程会从数据库中获取数据并回写到缓存中。在系统刚上线时,可以通过预热机制将部分热点数据预先加载到缓存中,以避免缓存击穿问题。

5. 总结

​ 缓存穿透、缓存雪崩和缓存击穿是缓存系统中常见的三大问题。通过合理设置缓存过期时间、使用互斥锁、布隆过滤器以及后台线程更新缓存等策略,可以有效缓解这些问题,提升系统的稳定性和性能。在实际应用中,应根据具体业务场景选择合适的解决方案,以确保系统的高效运行。


http://www.ppmy.cn/news/1573671.html

相关文章

【JavaEE进阶】MyBatis通过XML实现增删改查

目录 🎍前言 🍀配置连接字符串和MyBatis 🍃写持久层代码 ​🚩添加mapper接口 🚩添加UserInfoMapper.xml 🚩单元测试 🌲查(Select) 🚩结果映射 🌴增(Insert&…

AStar低代码平台RpcServiceBase的应用:客户端事务管理

由于AStar平台是基于RPC协议与AStar后端服务进行通讯,而又非常接近常规BS的编码方式,直接写SQL即可对数据库进行操作,那么如果有若干个访问需要在同一事务中进行的,如何处理?比如先生成临时表,再对临时表进…

索引以及索引底层数据结构

一、什么是索引? 索引(index)是数据库高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构(B树),这些数据结构以某种方式指向真在…

详细介绍:封装简易的 Axios 函数获取省份列表

目录 关键步骤: 完整代码(html): 代码解析: 程序运行结果: 本示例展示了如何通过封装一个简易的 myAxios 函数来模拟 axios 的功能,使用原生的 XMLHttpRequest(XHR)对…

青少年编程都有哪些比赛可以参加

Python小学生可参加的赛事: 电子学会青少年编程考级、中国计算机学会编程能力等级认证、蓝桥杯、 信奥赛CSP-J/S初赛/NOIP(推荐C)、编程设计、信息素养、科技创新赛; 升学助力(科技特长生、大学)、企业、出国留学; python比赛&am…

基于Flask的第七次人口普查数据分析系统的设计与实现

【Flask】基于Flask的第七次人口普查数据分析系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 基于Flask的人口普查可视化分析系统 二、项目界面展示 登录/注册 首页/详情 …

Linux 常用命令 - echo 【输出一行文字】

简介 echo 命令源自英文单词 “echo”,意为“回声”或“反馈”。在 Linux 系统中,它主要用于在终端显示一行文字,是一种输出字符串或变量到标准输出(通常是屏幕)的简单方式。这个命令在显示信息、调试脚本以及组合其他…

html css js网页制作成品——HTML+CSS+js茉酸奶的茶网页设计(5页)附源码

目录 一、👨‍🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML