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

【Redis典型应用——缓存详解】

系列文章目录


文章目录

  • 系列文章目录
  • 一、缓存基础知识
    • 1.什么是缓存
    • 2.为什么用Redis作为缓存
  • 二、缓存更新策略
    • 1.定期生成
      • 1.实现逻辑:
      • 2.优点和不足
    • 2.实时生成
      • 1.实现逻辑:
      • 2.缓存淘汰策略:
  • 三、缓存注意事项缓存预热,缓存穿透,缓存雪崩和缓存击穿
    • 1.缓存预热
    • 2.缓存穿透
      • 一、什么是缓存穿透?
      • 二、缓存穿透的 3 个核心成因
      • 三、解决缓存穿透的 3 个实用方案
    • 3.缓存雪崩
      • 二、产生的原因:
      • 三、解决方案
    • 4.缓存击穿
      • 二、缓存击穿的核心成因
      • 三、解决方法


一、缓存基础知识

1.什么是缓存

缓存不是某一种工具,而是一种 “数据存储策略”,核心逻辑是 “把高频使用的数据,放到更快的存储介质里,方便后续快速取用”。

可以用生活例子理解:
比如超市会把 “常买的零食、饮料” 放在入口的货架(快取区),而不常买的大米、面粉放在仓库(慢取区)。这里的 “入口货架” 就是 “缓存”,目的是让顾客不用跑仓库,更快拿到商品。
对应到计算机里:“仓库” 是数据库(如 MySQL,存在磁盘,读写慢),“入口货架” 就是缓存(存在内存,读写快),高频访问的数据(如首页商品、用户 Session)会先存到缓存里,后续请求直接查缓存,不用查数据库。

注意:缓存的访问速度是更快,但是相对的空间往往不足,所以大部分只存放热点数据

2.为什么用Redis作为缓存

一般在网站中,我们经常会使用关系型数据库(比如MySQL)来存储数据,虽然能存储的数据多,但性能不高。

  • 数据库数据存储在硬盘上,硬盘的IO速度并不快,尤其还是随机访问。
  • 如果查询不能命中索引,就需要进行表的遍历,会大大增加IO次数。
  • 关系型数据库对于SQL的执行会做一系列的解析,校验,优化工作。
  • 如果是复杂的查询,例如联合查询,还需要笛卡尔积操作,效率会降低很多。

如何让数据库承担更大的并发量?核心思路主要是两个:
1.开源:引入更多机器,部署更多数据库实例,构成数据库集群(主从复制、分库分表等)。
2.节流引入缓存,用其他方式保存经常访问的热点数据,从而降低直接访问数据库的请求数量。
Redis就是一个用作数据缓存的常见方案

Redis优点:

  • 速度快:数据存于内存,读写速度达 10 万 +/ 秒,远超数据库(磁盘 IO)。
  • 支持多数据结构:不止存字符串,还能存 Hash、List、Set 等,适配不同缓存场景(比如用 Hash 存用户信息,List 存消息队列)。
  • 高可用:支持主从复制、哨兵、集群,避免缓存单点故障。
  • 可持久化:能把内存数据存到磁盘,重启后数据不丢失(避免缓存全量重建)。

如下图所示:

在这里插入图片描述

  1. 客户端访问业务服务器,发起查询请求。
  2. 业务服务器先查询 Redis,看想要的数据是否在 Redis 中存在。
  3. 如果已经在 Redis 中存在,就直接返回,此时不必访问 MySQL。
  4. 如果在 Redis 中不存在,再查询 MySQL。按照 “二八定律”,只需要在 Redis 中放 20% 的热点数据,就可以使 80% 的请求不再真正查询数据库。

二、缓存更新策略

1.定期生成

缓存数据按 “固定时间间隔” 更新,不管数据是否变化。典型应用如搜索引擎热词、常规商品推荐等场景。

1.实现逻辑:

以 “搜索引擎热词缓存” 为例,完整流程如下:
1.日志记录访问数据:
先将用户的访问行为(如搜索框输入的查询词)以日志形式持久化(若数据量大,可存储在分布式系统 HDFS 中)。
离线统计热点数据
2.用大数据工具(如 Hadoop MapReduce、Python 脚本)对日志进行分析:
统计 “每个词的访问频率”,按频率降序排序;
提取前 20% 的 “热点词”(符合二八定律,少量数据承接大部分访问)。
3.定时任务同步到 Redis 缓存
编写离线脚本(如 Shell、Python),通过定时任务(Crontab、Quartz 等) 按周期(如每天凌晨)执行:

  • 从数据库 / 数据仓库中拉取 “热点词对应的搜索结果”;

  • 用SET key value EX 86400(设 1 天过期)将数据写入 Redis,完成缓存更新。

比如每天凌晨 2 点同步一次商品库存到 Redis,每 30 分钟刷新一次首页推荐列表 —— 核心是 “到点就更”,不依赖实时数据变化。

2.优点和不足

优点:
1.实现逻辑清晰:从 “日志记录→统计分析→缓存同步” 全流程可拆解,方便开发和排查问题(比如 Redis 中缓存了哪些热词,可通过脚本和日志回溯)。
2.资源消耗可预测:定时任务按固定时间执行,不会因突发流量导致缓存或数据库压力陡增。
3.适配 Redis 特性:可结合EXPIRE命令设置过期时间,避免缓存长期占用内存;若任务执行失败,还可通过 “重试机制” 或 “兜底查询”(缓存过期后读数据库回写)保障数据可用。

不足:
1.无法响应突发热点:若出现突发性事件(如春节晚会的临时热词),定期更新的缓存无法及时承接流量,可能导致数据库压力骤增。
2.时效性滞后:数据更新周期越长(如按月更新),缓存与实际数据的偏差可能越大。

2.实时生成

1.实现逻辑:

先给缓存设定容量上限(可通过 Redis 配置文件的 maxmemory 参数设定)。
接下来用户每次查询:

  • 若在 Redis 查到,直接返回。
  • 若 Redis 中不存在,从数据库查询,并将结果写入 Redis。
  • 若缓存已满(达到上限),触发缓存淘汰策略,淘汰一些 “相对不那么热门” 的数据。

2.缓存淘汰策略:

FIFO(先进先出)
淘汰缓存中存在时间最久的数据。举例:超市货架补货时,先把最早摆放的商品下架,上新最近到货的商品。
LRU(最久未使用)
记录每个 key 的最近访问时间,淘汰最近访问时间最老的 key。举例:手机后台 APP 清理,很久没打开的 APP 会被优先清理掉。
LFU(最少访问次数)
记录每个 key 最近一段时间的访问次数,淘汰访问次数最少的 key。举例:公司食堂窗口,学生光顾次数最少的窗口,会优先被调整或替换。
Random(随机淘汰)
从所有 key 中随机选一个淘汰。

理解淘汰策略:假设你手机里装了上百个 APP(相当于数据库全量数据),但常用的就那么几个(比如微信、抖音、外卖 APP,相当于缓存里的热点数据)。新出了一款超火的手游,你想下载,就得卸载一个旧 APP。该淘汰谁呢?
FIFO(先进先出):最早下载的 APP(比如刚买手机时装的 “万年历”),因为存在时间最久,被你卸载。
LRU(最久未使用):统计最近使用时间 —— 相册(一周前用过)、地图(昨天用过)、读书 APP(两周前用过)、股票软件(一个月前用过)。股票软件最久没被使用,被卸载。
LFU(最少访问次数):统计最近一个月的使用次数 —— 相册(3 次)、地图(15 次)、读书 APP(1 次)、股票软件(10 次)。读书 APP 使用次数最少,被卸载。
Random(随机淘汰):随机挑一个 APP,比如随机到相册,就把相册卸载了。

三、缓存注意事项缓存预热,缓存穿透,缓存雪崩和缓存击穿

1.缓存预热

概念:缓存预热的核心是在 Redis 缓存 “空” 或失效时,提前加载热点数据到 Redis,避免 MySQL 直接承压,本质是为 Redis 快速建立 “防护屏障”,适配 Redis 作为 MySQL 缓存的典型场景。

当 Redis 处于以下两种关键状态时,缓存能力基本失效:
Redis 刚启动:内存中无任何缓存数据,所有请求会直接穿透到 MySQL。
Redis 大批 key 失效:如缓存雪崩导致大量 key 同时过期,短时间内缓存 “空窗”。
此时,提前将 “热点数据” 主动写入 Redis,让 Redis 快速具备承接请求的能力,减少 MySQL 的直接访问量,这一操作就是缓存预热。它不需要等待用户请求触发 “查数据库→回写缓存” 的流程,而是主动为 Redis “填充弹药”。
注意:热点数据基于之前介绍的统计方式生成即可。这份热点数据不一定要那么 “准确”,只要能帮助 MySQL 抵挡大部分请求就行。随着程序运行,缓存的热点数据会逐渐自动调整,以更适应当前情况。

2.缓存穿透

概念:缓存穿透的核心是访问的 key 在 Redis 和数据库中均不存在,导致请求绕过缓存直接冲击数据库,长期会造成数据库压力过载,是 Redis 缓存架构中的典型风险点。

一、什么是缓存穿透?

当用户发起查询请求时,若满足以下两个条件,即构成缓存穿透:
目标 key 在 Redis 中不存在(缓存未命中);
该 key 在数据库(如 MySQL)中也不存在;
由于 key 在数据库中无数据,无法回写到 Redis,后续相同请求会持续绕过缓存,重复访问数据库,导致数据库承担不必要的高频请求压力。

二、缓存穿透的 3 个核心成因

缓存穿透并非偶然,主要源于业务设计、操作失误或恶意攻击,具体可分为三类:

  1. 业务设计不合理:缺少参数合法性校验环节,导致非法 key 被允许查询。
    例:查询用户信息时,未校验用户 ID 格式(如允许 “ID=-1”“ID=abc” 这类无效值),这类 key 在 Redis 和数据库中均不存在,会持续触发穿透。
  2. 开发 / 运维误操作:不慎删除数据库中的部分数据,导致原本存在的 key 变为 “双不存在”。
  3. 黑客恶意攻击:通过批量发送不存在的 key 请求,蓄意消耗数据库资源。

三、解决缓存穿透的 3 个实用方案

针对上述成因,需从 “拦截非法请求”“避免重复穿透”“提前判定存在性” 三个维度设计解决方案,落地性强且覆盖大部分场景:

  1. 严格校验查询参数合法性:在业务层前置拦截无效 key,从源头减少穿透请求。

  2. 缓存 “不存在的 key”(空值缓存):对数据库中不存在的 key,在 Redis 中存储空值,避免后续重复访问数据库。
    操作逻辑:
    当数据库查询结果为空时,用SET key “” EX 3600(设 1 小时过期)将空值写入 Redis;后续相同请求会命中 Redis 的空值,直接返回,无需访问数据库;

  3. 用布隆过滤器前置判定 key 存在性:在缓存前加一层布隆过滤器,提前过滤 “绝对不存在的 key”。
    操作逻辑:
    初始化时,将数据库中所有有效 key(如所有用户 ID、商品 ID)存入布隆过滤器(本质是一个二进制数组,通过哈希算法标记 key 存在);
    用户请求时,先通过布隆过滤器判定 key 是否存在:
    若过滤器判定 “不存在”,直接返回,不进入 Redis 或数据库;
    若判定 “可能存在”(布隆过滤器有极小误判率),再继续查询 Redis 和数据库;

优势:布隆过滤器占用内存极小(百万级 key 仅需几 MB),判定速度快(微秒级),能有效拦截绝大多数不存在的 key。

3.缓存雪崩

缓存雪崩的核心是Redis 缓存的 “防护层” 短时间内大面积失效,导致原本由缓存承接的请求瞬间全部涌向 MySQL,造成数据库压力骤增甚至直接宕机,是高并发场景下缓存架构的致命风险。

二、产生的原因:

  1. Redis 服务本身不可用(缓存层整体宕机)
    Redis 作为缓存核心,若自身出现故障,会导致所有依赖 Redis 的请求直接穿透到 MySQL
  2. 大量 Redis key 同时过期(缓存数据集体失效)
    这是更常见的雪崩场景,核心原因是 “短时间内缓存的大量 key 设置了相同过期时间”,到期后集体失效。

三、解决方案

  1. 部署高可用 Redis 集群,搭配完善监控报警。
  2. 优化 Redis key 的过期时间,避免集体失效。
    核心思路是 “打散 key 的过期时间”,不让大量 key 在同一时间到期,从源头减少雪崩风险。
    例如给过期时间添加随机因子(最常用):
    操作逻辑:在设置过期时间时,不使用固定值,而是在基础过期时间上叠加一个随机数,让 key 的过期时间分散开;

4.缓存击穿

概念:它是单一热点 key 突然过期导致大量请求集中冲击数据库的特殊场景,属于缓存雪崩的 “定向缩小版”,需重点与穿透、雪崩做区分。

二、缓存击穿的核心成因

所有缓存击穿的根源都指向 “热点 key 的缓存突然不可用”,唯一触发条件是:
key 是高频访问的热点数据:该 key 的访问量远高于其他 key(如占总请求量的 30% 以上),是流量核心;
key 突然过期 / 被删除

三、解决方法

  1. 热点 key “永不过期”(主动更新避免失效)
    核心是 “不给热点 key 设固定过期时间,用定时任务主动同步数据”,从源头杜绝 “过期” 问题。
    操作逻辑:
    优势:彻底避免热点 key 过期,无需担心击穿风险;
    注意点:需确保定时任务的稳定性(如加重试机制),若任务失败,可临时触发 “手动同步”,避免 Redis 存旧数据。
  2. 分布式锁限流(限制数据库并发请求)
    核心是 “当热点 key 过期时,用分布式锁控制仅 1 个请求去查数据库,其他请求等待重试”,避免数据库被瞬间压垮,将服务降级。
    优势:无需提前识别热点 key,适合热点 key 动态变化的场景;
    注意点:锁的过期时间需大于 “查 MySQL + 写 Redis” 的耗时(如 5 秒足够),避免锁提前释放导致多个请求查数据库。
    3. 热点 key 提前预热(主动填充缓存)
    核心是 “在热点 key 可能过期前,提前用脚本或任务更新缓存”,属于 “防患于未然” 的前置方案,与缓存预热逻辑一致。
    优势:无锁竞争开销,用户请求无感知,体验更好;
    适用场景:热点 key 的过期时间固定、可预测(如每日固定时间过期的活动商品)。
http://www.dtcms.com/a/528211.html

相关文章:

  • 阮一峰《TypeScript 教程》学习笔记——模块
  • 第 09 天:文件传输 (SCP, SFTP, rsync, FTP, NFS)
  • pandas 和 numpy相关函数详解
  • 酵母 cDNA 文库:解码基因表达与功能研究的核心工具
  • Win10使用WSL2安装ubuntu22.04
  • macos 下 docker使用方法 新手教程
  • t恤定制网站哪个网站是做红酒酒的
  • 玉林网站建设培训wordpress美术馆插件
  • 一个大型 3A 游戏的开发流程是怎么样的?
  • 智能性能分析:AI大模型识别性能瓶颈并提出改进建议
  • Flutter 中使用 Flame + flame_forge2d 的注意事项清单
  • SpringBoot教程(安装篇):Elasticsearch及可视化工具安装(Windows环境)
  • 华为OD机试双机位A卷 - 商品推荐多属性排序 (C++ Python JAVA JS GO)
  • 延安市违法建设举报网站深圳宝安网站推广
  • Mac Nginx安装、启动、简单命令(苍穹外卖、黑马点评前端环境搭建)
  • 新乡哪有做网站的北京seo执行
  • GitHub等平台形成的开源文化正在重塑林语堂
  • 鸿蒙分布式软总线通信协议详解
  • 建立网站的技术做谷歌seo要发大量文章吗
  • 第7章 muduo编程示例(5)
  • 微软输入法词库拓展600w(win11)
  • 解决虚拟机安装的Ubuntu20.04.6 LTS 不能复制粘贴问题
  • Linux中系统调用sys_access函数的实现
  • 微波加热内部温度场的电磁−热耦合模拟
  • 2024ICPC上海
  • 专业制作网站多少钱成品网页网站
  • Linux(LDAP服务)
  • 安卓旧机变服务器,KSWEB部署Typecho博客并实现远程访问:cpolar内网穿透实验室第645个成功挑战
  • 无需云服务的家庭相册:OpenHarmony 上的 Rust 实践
  • OpenHarmony后台服务开发指南:ServiceAbility与ServiceExtensionAbility全解析