【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,改为后台刷新。
  • 逻辑过期:缓存里存过期时间,过期后先返回旧值,同时异步刷新。
  • 随机提前刷新,避免集中失效。
相关推荐
OceanBase数据库官方博客10 小时前
常州公积金采用OceanBase,三年稳定运行并实现智慧服务新范式
数据库·oceanbase
深念Y10 小时前
理解大模型API缓存机制:从Claude Code的缓存失效到DeepSeek的硬盘缓存
缓存·ai·api·提示词·kvcache·vibecoding·claudecode
白雪落青衣10 小时前
BUU SQL COURSE 1 sql注入
数据库·sql·web安全·网络安全
徒手猫10 小时前
SQL CTE 从零到一:理解与实战
数据库
有味道的男人10 小时前
Open Claw对接小红书笔记详情
数据库·笔记
共绩算力10 小时前
第四辑:8 张「印刷品与示意图」——几何海报到工间操
前端·数据库·人工智能·共绩算力
guslegend11 小时前
1.Redis服务搭建
数据库·redis·bootstrap
半夜修仙11 小时前
Redis中ZSet数据类型的常见命令
数据库·redis·缓存
毋语天11 小时前
FastAPI 终极实战:ORM 数据库、RESTful 设计、中间件与依赖注入
数据库·中间件·restful·fastapi