当前位置: 首页 > news >正文

缓存三剑客问题

我们来详细聊聊经典的“缓存三剑客”问题。这是指在使用缓存(尤其是 Redis 或 Memcached)时,最常遇到且对系统危害最大的三种典型问题:​缓存穿透、缓存击穿、缓存雪崩

理解并解决这三个问题,是构建高可用、高性能系统的关键。


核心概念:为什么要用缓存?

首先,快速回顾缓存的作用:为了缓解数据库(如 MySQL)的读写压力,将频繁访问的“热数据”存放在读写速度极快的内存中(缓存)。数据的查询顺序变为:​先查缓存,缓存未命中再查数据库,并将结果写入缓存

“缓存三剑客”问题就出现在这个流程的异常情况中。


第一剑:缓存穿透

1. 问题描述

缓存穿透是指查询一个数据库中根本不存在的数据。由于数据不存在,缓存中自然也不会有(缓存未命中),导致这个请求会直接穿透缓存,每次都要去数据库查询。

  • 关键特征​:数据在数据库和缓存中都不存在。

  • 危害​:如果有人恶意发起大量这类请求(比如用不存在的用户ID查询用户信息),会瞬间给数据库带来巨大压力,甚至导致数据库宕机。

2. 解决方案
  1. 缓存空对象

    • 做法​:即使从数据库没查到,也向缓存中写入一个空值(如 null),并设置一个较短的过期时间(例如 3-5 分钟)。

    • 优点​:实现简单,能有效应对短期的大量攻击。

    • 缺点​:可能会在缓存中存储大量无意义的空键,占用内存;可能存在短期数据不一致(比如数据后来被录入了,但缓存里还是空值)。

  2. 布隆过滤器

    • 做法​:在缓存之前,设置一个布隆过滤器。布隆过滤器是一个高效的数据结构,用于快速判断“某个元素一定不存在”或“可能存在”于某个集合中。

    • 流程​:

      1. 将所有可能查询的数据的 key 哈希后映射到布隆过滤器的位数组中。

      2. 请求来时,先通过布隆过滤器判断 key 是否存在。

        • 如果不存在,则直接返回空,拒绝访问数据库。

        • 如果存在,才继续后续的缓存查询流程。

    • 优点​:内存占用极小,能从根本上彻底解决穿透问题。

    • 缺点​:实现稍复杂;有误判率(“可能存在”意味着它可能会把一些合法的、但不在过滤器里的新 key 误判为不存在,但不会误判存在的数据为不存在);数据变更时维护布隆过滤器较麻烦。


第二剑:缓存击穿

1. 问题描述

缓存击穿是指一个访问非常频繁的“热点数据”​​(比如某明星的微博)在缓存过期(失效)的瞬间。由于这个 key 可能被大量并发请求访问,在它失效的瞬间,所有对这些数据的请求都会穿透缓存,直接打到数据库上,仿佛缓存被“击穿”了一个洞。

  • 关键特征​:数据存在,但缓存刚好过期。key 是“热点”。

  • 危害​:在热点 key 失效的瞬间,巨大的并发可能压垮数据库。

2. 解决方案
  1. 设置热点数据永不过期

    • 做法​:对于极热点的 key,可以不对其设置过期时间。然后通过后台任务或程序逻辑,在数据更新时主动刷新缓存。

    • 优点​:简单,一劳永逸。

    • 缺点​:需要人工识别热点数据;数据一致性需要靠逻辑维护。

  2. 互斥锁

    • 做法​:当缓存失效时,不立即去查询数据库。而是先尝试获取一个分布式锁(如用 Redis 的 SETNX命令)。只有一个线程能成功获取锁,这个线程负责去查询数据库并重建缓存。其他未获取到锁的线程则等待一段时间后重试查询缓存。

    • 优点​:能很好地保护数据库,逻辑严谨。

    • 缺点​:实现复杂;如果获取锁的线程挂掉,可能需要处理锁超时;性能上有一定损耗(等待)。

  3. 逻辑过期

    • 做法​:不给缓存数据设置物理过期时间,而是在缓存 value 中额外存储一个逻辑过期时间。当业务线程发现数据逻辑上已过期时,它不会立即重建缓存,而是尝试获取互斥锁。拿到锁的线程会启动一个新线程去异步重建缓存,而自己则返回旧的、已过期的数据。其他线程在锁被占用期间,也直接返回旧数据。

    • 优点​:性能极佳,用户无感知,永远有数据返回。

    • 缺点​:实现最复杂;会有一段时间的数据延迟(返回旧数据)。


第三剑:缓存雪崩

1. 问题描述

缓存雪崩是指缓存中大量的 key 在同一时间点或时间段内集中失效,或者缓存服务直接宕机。导致所有原本应该访问缓存的请求,瞬间全部涌向数据库,数据库无法承受巨大的压力而崩溃,进而导致整个系统崩溃,就像雪崩一样。

  • 关键特征​:大量 key 同时失效 或 缓存服务不可用。

  • 与击穿的区别​:击穿是单个热点 key 失效,雪崩是大量 key 同时失效。

2. 解决方案
  1. 设置随机的过期时间

    • 做法​:在为缓存数据设置过期时间时,在基础过期时间上加上一个随机值(如 1-5 分钟的随机数)。这样可以让 key 的过期时间尽量分散,避免同时失效。

    • 优点​:简单有效,是预防雪崩的首选方案。

  2. 构建高可用的缓存集群

    • 做法​:通过 Redis 的哨兵模式或集群模式,实现缓存服务的高可用。即使个别节点宕机,整个集群仍然可以提供服务。

    • 目的​:防止因缓存服务宕机而引发的雪崩。

  3. 服务熔断与降级

    • 做法​:当应用系统检测到数据库压力过大或响应过慢时,启动熔断机制,暂时停止访问数据库,直接返回预设的默认值(如“系统繁忙,请稍后再试”)或兜底数据。给数据库“止血”,等缓存服务恢复后,再关闭熔断。

    • 目的​:牺牲部分用户体验和非核心功能,保证核心业务和系统整体不崩溃。

  4. 持久化存储预热

    • 做法​:在缓存服务重启或大规模失效后,系统正式对外提供服务前,先通过一个脚本或程序,将高频访问的数据提前加载到缓存中。


总结与对比

问题类型

核心原因

关键特征

主要解决方案

缓存穿透

查询不存在的数据

数据库和缓存中都没有

1. 缓存空对象
2. 布隆过滤器

缓存击穿

热点 key​ 突然过期

单个热点 key 失效,并发高

1. 永不过期
2. 互斥锁
3. 逻辑过期

缓存雪崩

大量 key​ 同时失效或缓存宕机

大规模缓存失效,系统级故障

1. 设置随机过期时间
2. 缓存高可用集群
3. 服务熔断与降级

应对法则​:

  1. 防穿透​:守住第一道门,判断请求是否合法。

  2. 防击穿​:保护热点,避免单点并发。

  3. 防雪崩​:分散风险,保证服务可用。

在实际项目中,通常需要组合运用这些策略,才能构建一个健壮的缓存系统。

http://www.dtcms.com/a/499009.html

相关文章:

  • 构建AI智能体:六十七、超参数如何影响大模型?通俗讲解原理、作用与实战示例
  • timm教程翻译:(一)Overview
  • 手写Spring第5弹:告别项目混乱:用Maven构建标准Java项目目录结构
  • Vue3 表单输入绑定
  • 手机app制作网站网站后台尺寸一般做多大的
  • C程序中的选择语句
  • OpenCV进阶:图像变换、增强与特征检测实战
  • 自己做的网站怎样对接支付宝php餐饮美食店网站源码 生成html
  • 【大数据技术实战】Kafka 认证机制全解析
  • Android14源码移植到Android16的应用报错分析说明
  • 13万枚比特币被没收。。。
  • 企业网站规划案例网页微信版传输助手
  • 用Trae自动生成一个围棋小程序
  • 聊天室项目开发——etcd的安装和使用
  • 小林coding | MySQL图解
  • 大模型-智能体-【篇二:多智能体框架】
  • C语言文件操作全面解析:从基础概念到高级应用
  • 人大计算金融课程名称:《机器学习》(题库)/《大数据与机器学习》(非题库) 姜昊教授
  • 网站建设的策划文案设计公司网站公司详情
  • VMD-LSTM: 医疗时序数据降噪与预测优化课件分析(2025年6月教学版)
  • iOS Runtime之 KVO
  • ZigBee中的many-to-one和link status(1)
  • 【WRF-CMAQ第二期】WRF-CMAQ 测试案例安装与运行
  • 汕头seo网站排名免费制作网页的软件有哪些
  • 韩国设计网站推荐yandex搜索引擎入口
  • 2025年机器视觉软件平台哪个好?场景适配视角下的优质实例解析
  • 【C++/Lua联合开发】 (一) Lua基础知识
  • 从前序与中序遍历序列构造二叉树
  • 学习go语言
  • Linux中工作队列使用