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

Redis 缓存机制 及问题场景 及解决方案

Redis

  • Redis 作为缓存的核心机制
  • Redis 缓存击穿 (Cache Breakdown)
  • Redis 缓存穿透 (Cache Penetration)
  • Redis 缓存雪崩 (Cache Avalanche)
  • 解决方案
    • 1.缓存空对象 (Cache Null)
    • 2.布隆过滤器 (Bloom Filter)
    • 3.接口层校验
  • 总结

Redis 的缓存机制和缓存穿透问题

Redis 作为缓存的核心机制

Redis 的核心价值之一就是作为高性能的缓存层,位于应用程序和持久化存储(通常是数据库如 MySQL, PostgreSQL)之间。它的工作原理和优势如下:

1.核心思想:

  • 快速访问: 利用内存的高速读写能力(远快于磁盘),存储经常被访问的数据副本。
  • 减轻后端压力: 拦截对数据库的重复查询,降低数据库的负载,提高整体系统吞吐量和响应速度
  • 数据局部性: 服务于热点数据(被频繁访问的数据)。

2.常见缓存读写策略 (Cache-Aside / Lazy Loading):

读操作 (Read): 应用程序首先尝试从 Redis 缓存中读取数据
1.缓存命中 (Cache Hit): 如果数据存在于 Redis 中,直接返回给应用程序

2.缓存未命中 (Cache Miss): 如果数据不在 Redis 中:
a. 应用程序从数据库中查询所需数据
b.将查询到的数据写入 Redis 缓存(通常设置一个过期时间 TTL)
c.将数据返回给应用程序

写操作 (Write): 应用程序直接更新数据库
1.失效 (Invalidate): 同时使 Redis 缓存中对应的数据失效(删除对应的 Key)。下次读取时,会触发缓存未命中流程,从数据库加载最新数据到缓存。
2. 写穿 (Write-Through): 应用程序同时更新数据库和缓存(确保缓存一致性,但写操作变慢)。更常见的是上面的失效策略

关键点: 缓存数据通常设置一个过期时间 (TTL - Time To Live) 这保证了:
1.即使缓存更新失败(写失效未成功),旧数据会在一定时间后被自动清除,下次读取会加载新数据
2.防止冷数据(不再被频繁访问的数据)长期占用宝贵的内存空间

3.Redis 作为缓存的优势:
* 极高的性能: 基于内存,读写速度极快(微秒级)
* 丰富的数据结构: String, Hash, List, Set, Sorted Set 等,能灵活存储各种形式的数据
* 持久化选项: RDB快照和AOF日志,虽然缓存数据通常不强调持久化,但提供了一定的可靠性选项
* 高可用与扩展: Redis Sentinel(主从故障切换), Redis Cluster(分布式分片)。
* 原子操作与 Lua 脚本: 支持复杂操作的原子性执行

Redis 缓存击穿 (Cache Breakdown)

缓存击穿 (Cache Breakdown): 指的是一个热点 Key(大量并发访问)在缓存过期的瞬间,大量请求同时发现缓存失效,瞬间穿透到数据库去查询同一个数据,造成数据库压力陡增。 关键: 数据存在,只是缓存恰好失效了,并且是热点数据

Redis 缓存穿透 (Cache Penetration)

缓存穿透 (Cache Penetration): 查询的数据根本不存在于数据库(和缓存),无论缓存是否过期。关键: 请求的数据本身就不存在

1.缓存穿透的场景:

  • 业务逻辑漏洞/参数错误: 用户输入了非法的参数(如不存在的用户 ID、商品 ID)。
  • 恶意攻击: 黑客故意构造大量数据库中根本不存在的 Key 发起请求,目的是压垮数据库。

2. 本质问题:

  • 这些查询本身是无效的(请求的数据根本不存在)。
  • 恶意攻击者或程序错误可能故意、大量地发起这类无效查询

3. 造成的影响:

  • 数据库压力剧增: 大量无效请求直接打到数据库,消耗数据库连接和 CPU 资源
  • 性能下降: 数据库忙于处理这些无效查询,导致处理正常查询的能力下降,整体系统响应变慢
  • 潜在宕机风险: 在极端情况下,如果攻击流量足够大,数据库可能因不堪重负而宕机

Redis 缓存雪崩 (Cache Avalanche)

指在某一时刻,缓存中大量的 Key 同时过期失效,导致所有对这些 Key 的请求瞬间都穿透到数据库,造成数据库压力巨大甚至崩溃

4.与缓存击穿、缓存雪崩的区别:

  • 缓存击穿 (Cache Breakdown): 指的是一个热点 Key(大量并发访问)在缓存过期的瞬间,大量请求同时发现缓存失效,瞬间穿透到数据库去查询同一个数据,造成数据库压力陡增。 关键: 数据存在,只是缓存恰好失效了,并且是热点数据

  • 缓存雪崩 (Cache Avalanche): 指在某一时刻,缓存中大量的 Key 同时过期失效,导致所有对这些 Key 的请求瞬间都穿透到数据库,造成数据库压力巨大甚至崩溃。 关键: 大量不同的 Key 同时失效

解决方案

解决缓存穿透的核心思路是:识别并拦截这些针对不存在数据的无效请求,避免它们穿透到数据库

1.缓存空对象 (Cache Null)

做法: 当数据库查询返回为空(数据不存在)时,仍然将一个特殊的“空值”(如 null, "", 或特定标记对象)写入 Redis 缓存,并为其设置一个相对较短的过期时间(比如 1-5 分钟)

效果: 后续相同的无效请求在短时间内会命中这个缓存的空对象,直接返回(或按空数据处理),而不会访问数据库。防止缓存穿透而造成的数据库压力

优点: 实现简单,对代码侵入性小。
缺点:
1.内存浪费: 如攻击者构造大量不同的无效 Key,会导致缓存中存储大量无意义的空值,占用内存
2.短暂的数据不一致: 如果在空对象缓存有效期内,数据库中实际添加了这个数据,那么在空对象过期前,用户仍然会得到“不存在”的结果,这种情况可以在如果知道 Key 的前提下,通过在数据写入时主动清除对应的空值缓存来缓解

2.布隆过滤器 (Bloom Filter)

**布隆过滤器(Bloom Filter)**是一种空间效率极高的概率型数据结构,用于快速判断一个元素是否可能存在于某个集合中。它的核心优势在于用极小的内存空间实现快速查询,但代价是存在一定的误判率(False Positive)

原理: 布隆过滤器是一种空间效率极高的概率型数据结构。它利用多个哈希函数和一个大的位数组(Bit Array)来实现,核心组件:位数组(Bit Array)多个哈希函数(Hash Functions)
1.位数组(Bit Array)

  • 一个长度为 m 的二进制向量(初始值全为0),用于存储数据的存在性信息
  • 示例:[0, 0, 0, 0, 0, 0, 0, 0](假设 m=8

2.多个哈希函数(Hash Functions)

  • 一组 k 个独立的哈希函数(如 H1, H2, ..., Hk)。
  • 每个函数将输入元素映射到位数组的某个位置范围(范围:0m-1

工作流程
1. 添加元素(Insertion)

  • 将元素 x 分别通过 k 个哈希函数计算,得到 k 个哈希值:
    H1(x), H2(x), ..., Hk(x)
  • 将这些哈希值对 m 取模,得到位数组中的 k 个位置:
    P1 = H1(x) % m, P2 = H2(x) % m, ..., Pk = Hk(x) % m
  • 将位数组中这 k 个位置的值设为 1

示例

添加元素 "apple":
H1("apple") = 5 % 10 = 5
H2("apple") = 97 ('a') % 10 = 7设置位置 5 和 7 为 1:
[0, 0, 0, 0, 0, 1, 0, 1, 0, 0]

2. 查询元素(Lookup)

  • 对查询元素 y 执行相同的操作:
    计算 k 个位置:P1, P2, ..., Pk
  • 检查位数组中这些位置的值:
    • 如果所有位置的值均为 1 → 返回 "可能存在"可能存在误判
    • 如果任一位置的值为 0 → 返回 "一定不存在"绝对正确
此时位数组
[0, 0, 0, 0, 0, 1, 0, 1, 0, 0]检查位置 5 和 7 均为 1 → 返回 "可能存在"(正确)查询元素 "banana"(未插入)
H1("banana") = 6 % 10 = 6 → 位置 6 为 0
发现位置 6 为 0 → 返回 "一定不存在"(正确)查询元素 "grape"(未插入,但发生误判)
H1("grape") = 5 % 10 = 5 → 位置 5 为 1
H2("grape") = 103 ('g') % 10 = 3 → 位置 3 为 0
发现位置 3 为 0 → 返回 "一定不存在"(正确)查询元素 "mango"(未插入,误判场景):
假设 H1("mango") = 5(位置 5 已被设为 1)
假设 H2("mango") = 7(位置 7 已被设为 1)
两个位置均为 1 → 返回 "可能存在"(实际不存在,误判)

关键特性
1.空间效率极高:不存储元素本身,只存储 k 个比特位的状态
示例:
存储 1 亿个元素,误判率 1% 时,仅需约 114MB 内存(传统哈希表需 GB 级内存)
2.查询时间复杂度为 O(k)
仅需计算 k 次哈希并检查位数组,速度极快(常数时间)
3. 误判率(False Positive)
误判场景:
元素 z 不在集合中,但 k 个位置恰好被其他元素设为 1(哈希碰撞)
4.不支持删除操作
将某个位置从 1 改为 0 会影响其他映射到该位置的元素(导致漏判)
解决方案:
使用变种如 计数布隆过滤器(Counting Bloom Filter)(用计数器代替比特位)

布隆过滤器 (Bloom Filter)在缓存穿透中的应用:
1.系统启动时或数据变更时,将所有真实存在的有效 Key 预热到布隆过滤器中。
2.在查询缓存之前,先查询布隆过滤器
如果布隆过滤器说 Key 不存在(至少有一位是0),则直接返回“数据不存在”给客户端,无需查询缓存和数据库
如果布隆过滤器说 Key 可能存在(所有位都是1),则继续正常的缓存查询流程(查缓存 -> 未命中则查数据库 -> 回填缓存或缓存空值)。

优点:
空间效率极高: 存储海量 Key 的“存在”信息所需内存远小于直接存储 Key 本身。
查询效率极高: 判断 Key 是否“可能存在”非常快(常数时间复杂度 O(K))。
缺点:
误判率 (False Positive): 存在一定的概率,将不存在的 Key 误判为可能存在(所有位碰巧都被其他 Key 置1了)。这意味着无法完全避免穿透(误判时还是会去查库),但能拦截绝大部分无效请求。
无法删除: 标准的布隆过滤器不支持删除元素(删除一个 Key 会影响其他共享相同位的 Key)
可以使用变种如计数布隆过滤器 (Counting Bloom Filter)布谷鸟过滤器 (Cuckoo Filter) 来支持删除,但代价是更大的空间或计算开销。
需要预热: 需要将有效 Key 初始化到过滤器中。

3.接口层校验

做法: 在请求到达业务逻辑和缓存查询之前,在最外层(如 API 网关、Controller 层)对请求参数进行基础校验

例子:
1.检查用户 ID 是否符合格式(如必须是数字且在一定范围内)
2.检查商品 ID 是否存在非法字符。
3.对访问频率进行限制(Rate Limiting)。
4.黑名单过滤已知的攻击模式或 IP。
效果: 拦截掉一部分明显非法的请求,防止它们进入后续流程(包括缓存查询)。
优点: 简单直接,能有效拦截低级攻击和错误输入。
缺点: 无法防御精心构造的、参数格式合法的无效请求(如随机生成在合法范围内的不存在的 ID)

总结

  • Redis 缓存: 是提升系统性能的关键组件,通过内存存储热点数据,减少数据库访问。
  • 缓存穿透: 是查询不存在的数据导致请求绕过缓存直击数据库的问题,危害巨大。
  • 解决方案:
    • 缓存空对象: 简单有效,适用于已知的不存在 Key,但可能浪费内存且有短暂不一致性。
    • 布隆过滤器: 空间效率高,能高效拦截绝大部分无效请求,是防御大规模恶意攻击穿透的首选方案,但有误判率且需预热。
    • 接口层校验: 作为第一道防线,拦截明显非法请求,是必要的补充手段。
  • 实际应用: 通常组合使用这些方案。例如,在网关层做基础校验和限流,在业务层使用布隆过滤器拦截已知不存在的 Key,对于穿透布隆过滤器的请求(可能是误判也可能是新无效 Key),配合缓存空对象策略。

理解缓存穿透及其解决方案,对于构建高性能、高可用的基于 Redis 缓存的系统至关重要。

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

相关文章:

  • 接口自动化工具-SoapUI
  • kotlin
  • Ubuntu22.04下微星B850M主板 无wifi模块
  • AR 双缝干涉实验亮相:创新科技实验范式,开拓 AR 技术新局​
  • 传输层协议TCP、UDP
  • SpringBoot+Mybatis+MySQL+Vue+ElementUI前后端分离版:整体布局、架构调整(二)
  • 基于FPGA的累加算法实现
  • 2. 两数相加
  • 从零实现一个GPT 【React + Express】--- 【1】初始化前后端项目,实现模型接入+SSE
  • 领域驱动设计(DDD)重塑金融系统架构
  • Qt 与Halcon联合开发九:算法类设计与实现讲解(附源码)
  • AlphaEvolve:谷歌的算法进化引擎 | 从数学证明到芯片设计的AI自主发现新纪元
  • 告别“电量焦虑”,BLE如何提升可穿戴设备续航能力?
  • Flutter基础(前端教程④-组件拼接)
  • Linux NUMA调优实战:多线程程序加速方法
  • 电路研究9.3.10——合宙Air780EP中的AT开发指南:阿里云应用指南
  • Deepoc大模型:重构无人机认知边界的具身智能革命
  • 华为泰山服务器重启后出现 XFS 文件系统磁盘“不识别”(无法挂载或访问),但挂载点目录仍在且无数据
  • WPA2 与 WPA3:深入解析Wi-Fi安全协议
  • Linux网络:UDP socket创建流程与简单通信
  • 手机能用酒精擦吗?
  • 前端学习3--position定位(relative+absolute+sticky)
  • Android kotlin 协程的详细使用指南
  • SpringBoot校园外卖服务系统设计与实现源码
  • EXCEL链接模板无法自动链接到PowerBI?试试这个方法
  • 自动驾驶的“安全基石”:NVIDIA如何用技术守护未来出行
  • 最新 HarmonyOS API 20 知识库 重磅推出
  • 【计算机网络】王道考研笔记整理(1)计算机网络体系结构
  • 嘉立创黄山派下载watch ui demo 教程(sf32)
  • Modbus TCP转Profinet网关实现视觉相机与西门子PLC配置实例研究