【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,改为后台刷新。
  • 逻辑过期:缓存里存过期时间,过期后先返回旧值,同时异步刷新。
  • 随机提前刷新,避免集中失效。
相关推荐
阿狸猿13 小时前
论 NoSQL 数据库技术及其应用
数据库·nosql
FBI HackerHarry浩13 小时前
DataGrip2023.2.3默认保存的数据库和.sql文件在哪里?怎么修改默认路径?
数据库
袁小皮皮不皮13 小时前
3.HCIP OSPF补充知识(优化版)
服务器·网络·数据库·网络协议·智能路由器
运筹vivo@13 小时前
Python ContextVar 底层机制与内存模型拆解
前端·数据库·python
志栋智能14 小时前
超自动化巡检:知识沉淀与团队协作的新载体
大数据·运维·网络·数据库·人工智能·自动化
syt_biancheng14 小时前
Redis初识
数据库·redis·缓存
cmes_love14 小时前
股票逐笔level2历史行情下载十档订单薄五档tick分钟下载分享
数据库·区块链
仙俊红14 小时前
SQL 调优需要掌握的知识
数据库·sql
fofantasy15 小时前
NSK LH12AN 微型导轨技术手册
运维·网络·数据库·经验分享·规格说明书
杨运交15 小时前
[032][缓存模块]基于Redis Bitmap的用户行为统计实战:签到与日活分析
数据库·redis·缓存