【Redis | 第三篇】缓存(Cache)

目录

一、什么是缓存?

二、缓存更新策略

[2.1 主动更新的三种策略](#2.1 主动更新的三种策略)

三、缓存穿透

四、缓存雪崩

五、缓存击穿


一、什么是缓存?

缓存就是将极其耗时、计算昂贵或频繁访问的数据,临时存储在访问速度更快的介质中(通常是内存),以便下次请求时能直接获取,而无需重新计算或从慢速设备(如硬盘数据库)中读取。

二、缓存更新策略

业务场景:

  • 低一致性需求:使用内存淘汰机制。例如店铺类型的查询缓存。
  • 高一致性需求:主动更新,并以超时剔除作为兜底方案。例如店铺详情查询的缓存。

2.1 主动更新的三种策略

缓存主动更新有三种策略:Cache Aside Pattern、Read/Write Through Pattern、Write Behind Caching Pattern。

策略名称 核心运作机制 主要优点 主要缺点 适用场景
Cache Aside (旁路缓存) 应用程序同时负责维护数据库和缓存。 :先读缓存,未命中则读数据库并回写缓存。:先更新数据库,再删除缓存。 1. 资源利用率高:缓存中只保留实际被请求的数据。 2. 实现灵活:不依赖特定的缓存中间件特性,适用范围最广。 1. 代码侵入性强:应用层需要编写大量操作数据库和缓存的控制逻辑。 2. 极端并发风险:在特定的读写并发场景下,仍有极小概率出现数据不一致。 绝大多数常规 Web 业务(如电商、社交网络),是目前 Redis + MySQL 架构下最标准的做法。
Read/Write Through (读写穿透) 应用程序只和缓存层交互。缓存层封装了对数据库的操作。 :缓存未命中时,由缓存服务去查数据库并加载数据。 :应用更新缓存,缓存服务同步更新数据库。 1. 代码极简:对应用程序透明,应用层无需关心数据库同步逻辑。 2. 数据一致性高:缓存和数据库由底层服务同步控制。 1. 性能损耗:写操作需要同步等待数据库落盘,写入速度受制于数据库。 2. 门槛较高:大多数主流分布式缓存(如原生 Redis)不直接支持此模式,需要自行开发代理层或使用特定组件。 对数据一致性要求极高,且读多写少的场景;或者使用了原生支持该模式的本地/分布式缓存组件(如 Guava/Ehcache)。
Write Behind (异步写回) 应用程序只更新缓存,操作直接返回。缓存服务随后在后台异步、批量地将数据更新到数据库。 1. 极致写性能:应用所有的写操作都在内存中完成,响应极快。 2. 保护数据库:通过合并和批量写入,大幅降低数据库的 IO 压力。 1. 数据丢失风险极高:如果缓存节点在数据异步刷盘前宕机,数据将彻底丢失。 2. 强一致性无法保证:由于是异步写入,数据库数据会有明显的延迟。 3. 实现异常复杂:需要解决冲突、重试、持久化队列等问题。 写操作极其频繁且允许一定数据丢失的场景。例如:视频播放量统计、大规模实时日志收集、高并发秒杀系统中的初级计数。

使用Cache Aside来更新缓存有三个问题需要我们考虑:

1.删除缓存还是更新缓存?

  • 更新缓存:每次更新数据库都更新缓存,无效写操作较多
  • 删除缓存:更新数据库时让缓存失效,查询时再更新缓存

2.如何保证缓存和数据库的操作的同时成功和失败?

  • 单体系统,将缓存与数据库操作放在一个事务
  • 分布式系统,利用TCC等分布式事务方案

3.先操作缓存还是先操作数据库?

方案一中的线程一执行更新数据库的操作是很耗时的,在此时线程二要来查询数据库并写入缓存的可能性是很大的,很容易造成数据不一致的情况。方案二中线程一查询缓存并写入缓存的速度极快,此时线程二来更新数据库需要很长时间,当线程一将旧的数据库数据写入缓存后,尽管线程二同时更新数据库了,也是线程一先写入缓存的概率更大一些。因此我们选择先操作数据库,在删除缓存。

三、缓存穿透

缓存穿透就是指,请求的数据根本不存在,比如用户一直查 id=-1 或不存在的商品 id。

下图展示了两种解决缓存穿透的方案:

  • 缓存空值,比如 product:999 = null,TTL 设置短一点。
  • 使用布隆过滤器,先判断 id 是否可能存在。

四、缓存雪崩

缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

解决方案:

  • 给不同的Key的TTL添加随机值
  • 利用Redis集群提高服务的可用性
  • 给缓存业务添加降级限流策略
  • 给业务添加多级缓存

五、缓存击穿

缓存击穿也叫热点key问题,某个热点 key 过期瞬间,大量请求同时访问,全部打到数据库。

例如热门商品详情缓存刚好失效:

10万个请求 -> Redis 未命中 -> 数据库压力暴涨

解决办法:

  • 加互斥锁,只允许一个请求回源数据库。
  • 热点 key 不设置短 TTL,改为后台刷新。
  • 逻辑过期:缓存里存过期时间,过期后先返回旧值,同时异步刷新。
  • 随机提前刷新,避免集中失效。
相关推荐
XLYcmy1 小时前
核内调度问题的分层优化:缓存管理与性能均衡策略 模型评价 模型缺点与改进方向
缓存·ai·启发式算法·图神经网络·遗传算法·数模·模拟退火
我会尽全力 乐观而坚强1 小时前
MySQL库与表的操作
linux·数据库·mysql
lilihuigz1 小时前
产品附加选项插件WooCommerce Product Add-Ons:9种字段类型与3种定价模式提升销售 - 易服客工作室
数据库·mysql·wordpress插件·woocommerce扩展·定制选项
360智汇云2 小时前
Valkey 9.1上线:从Redis兼容到AI数据能力探索
数据库
标致的自行车2 小时前
Entity Framework之问题收集
jvm·数据库·oracle
啵啵鱼爱吃小猫咪2 小时前
Franka机械臂安装实时内核
数据库·postgresql
今天也是元气满满的一天呢3 小时前
从单机架构到负载均衡的互联网架构全流程
数据库·系统架构
SelectDB3 小时前
快手 AB 场景提速 145 倍,从 Spark 到 Apache Doris 的加速实践
数据库·spark·开源
SelectDB3 小时前
阶跃星辰 Agent 可观测实践:为什么 Trace 数据底座选择 SelectDB?
大数据·数据库·agent
冷静的楼房3 小时前
使用ThreadPool发起同步的调用
数据库