news 2026/7/8 12:15:38

Redis篇4—(Redis深度剖析):内存淘汰策略与缓存的三大“天坑”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis篇4—(Redis深度剖析):内存淘汰策略与缓存的三大“天坑”

在前面的文章中,我们聊了分布式锁、聊了持久化,这些都是在讲“怎么用好 Redis”。

但今天我们要聊一个更底层、更残酷的话题:资源限制与系统脆弱性

Redis 再快,它也是基于内存的。内存是昂贵的资源,不可能无限扩容。同时,Redis 作为数据库的挡箭牌,一旦它出了问题,数据库瞬间就会面临灭顶之灾。

今天这篇,我们就来把 Redis 的内存淘汰策略缓存击穿/穿透/雪崩彻底讲透。


一、 内存满了怎么办?(内存淘汰策略)

Redis 的性能虽然强悍,但它不是黑洞。在生产环境中,我们通常会在配置文件中设置maxmemory来限制 Redis 的最大内存使用量。

那么问题来了:当数据量存满了,新数据又要塞进来,Redis 该扔掉谁?

Redis 提供了 8 种策略,看起来眼花缭乱。其实作为博主,我建议你不要死记硬背,而是从“范围”“算法”两个维度去理解。

1. 维度一:你要对谁下手?(筛选范围)

Redis 并不总是对所有数据都“赶尽杀绝”,它把数据分为了两类圈子:

  • 圈子一:Volatile(临时工区 - 仅针对设置了 TTL 的 Key)

    • 含义:Redis 只会从设置了过期时间的 Key 中进行淘汰。

    • 场景:这非常适合“混合存储”场景。比如你的 Redis 里既存了必须持久化的重要配置(没设 TTL),又存了大量的临时缓存(设了 TTL)。当内存不足时,Redis 会很懂事地只清理那些本来就会过期的缓存,绝对不会碰你的重要数据。

  • 圈子二:Allkeys(全员区 - 针对所有 Key)

    • 含义:不管你设没设过期时间,一视同仁,大家都在被淘汰的范围内。

    • 场景:这是“纯缓存”模式的最佳选择。因为作为缓存,只要内存满了,没用的数据就该腾位置,不需要保留任何特权阶级。

2. 维度二:你要怎么挑?(筛选算法)

  • LRU (Least Recently Used)淘汰最久没被使用过的

    • 逻辑:你虽然进来的早,但最近 3 个月都没人查过你,留着浪费资源,请你走人。

  • LFU (Least Frequently Used)淘汰使用频率最低的

    • 逻辑:虽然你刚才被访问了一次,但你是这一年来唯一的访问,说明你不够热,请你走人。

  • Random随机。闭着眼瞎选一个删掉。

  • TTL剩余寿命最短。既然你马上就要过期了,不如我提前送你一程(仅适用于 Volatile 范围)。

3. 策略大盘点与选型建议

将上述两个维度组合,再加上默认策略,就构成了 8 种策略:

策略名筛选范围淘汰规则博主推荐场景
noeviction-不删除,直接报错(默认配置)适用于数据绝不能丢的场景,需配合完善的扩容监控。
volatile-lru有TTL的最久未用适用于Redis 既做缓存又做存储的混合场景。
volatile-lfu有TTL的最少频率同上。
volatile-random有TTL的随机删除极其少用。
volatile-ttl有TTL的即将过期哪怕没过期,只要快到了就删,不如 LRU 智能。
allkeys-lru所有Key最久未用最常用!适用于通用的缓存场景,保留热点数据。
allkeys-lfu所有Key最少频率适用于有些生僻数据很久才被访问一次的场景。
allkeys-random所有Key随机删除极其少用。

说明:

  • 绝大多数业务场景,直接闭眼选allkeys-lru

  • 因为缓存的本质就是“把热的数据留下”,LRU 是最符合这个直觉的算法。


二、 缓存的三大“天坑”:击穿、穿透、雪崩

Redis 就像一道堤坝,挡在脆弱的 MySQL 数据库前面。如果这道堤坝出了问题,洪水(高并发请求)就会直接冲垮数据库。

我们按照问题的**“刁钻程度”**,由点到面来分析。

1. 缓存击穿 (Cache Breakdown) —— “单点爆破”

简单来说就是热点key过期的瞬间,大量请求达到了DB。

这是最常见,但也最需要技术含量的场景。

  • 现象:

    某个 超级热点 Key(比如微博热搜、秒杀商品),并发量极高。在它 TTL 过期的一瞬间,几万个请求同时发现 Redis 没数据,同时冲向数据库去构建缓存。

    结果: 数据库瞬间被打死。

  • 解决方案:

    针对这个问题,我们有两种截然不同的思路。

    方案 A:互斥锁 (Consistency First)

    既然大家都要去查数据库,那就排队!

    • 思路:只允许一个线程去查询数据库并重建缓存,其他线程阻塞等待。

    • 流程

      1. 线程 1 发现缓存没数据。

      2. 线程 1 获取分布式锁(Mutex Lock)。

      3. 线程 1 去查库、写缓存、释放锁。

      4. 线程 2、3、4 在获取锁失败后,阻塞等待,或者休眠一会再重试(Double Check)。

    • 优点:数据一致性高。

    • 缺点:性能有损耗,大家都在等那一个人。

    方案 B:永不过期 + 逻辑过期 (Availability First)(就好像他本应该过期的,但是我留下了他用来保护数据库,反正我先返回给你,然后更新重置缓存)

    这个方案牺牲了一点点数据一致性,换取了极致的性能。这也是很多高并发系统的首选。

    • 核心思路

      • Redis 层面:Key不设置 TTL,所以物理上它永远不会过期(除非被淘汰)。

      • 业务层面:我们在 Value 的内容里,多存一个属性:expireTime(逻辑过期时间)。

    • 具体实现流程

      1. 查询缓存:请求命中缓存后,读取 Value。

      2. 判断过期:检查 Value 里的expireTime字段,看是否已过期。

      3. 未过期:直接返回数据,结束。

      4. 已过期

        • 获取锁:尝试获取互斥锁。

        • 开启异步线程:如果获取锁成功,说明我是“被选中”的那个人。我立马开启一个独立的异步线程去查询数据库、更新缓存(重置expireTime)、释放锁。

        • 返回旧值:无论是获取锁成功的当前线程,还是获取锁失败的其他线程,都不用等,直接把手里这份“已经过期”的旧数据返回给用户。

    • 说明:

      这种方案非常巧妙。它实际上是“悄悄地在后台更新”。用户在更新完成前的几百毫秒内,虽然看到的是旧数据,但系统响应速度极快,没有任何阻塞。

2. 缓存穿透 (Cache Penetration) —— “打在了空气上”

关键在⼀个透字,透过去了,即数据在 Redis 缓存和数据库中都不存在这样缓存永远 不会生效,请求都会打到数据库。(说白了,没得给你缓存的机会)

如果说击穿是“热点失效”,那穿透就是“恶意攻击”。

  • 现象:

    请求想要的数据,Redis 里没有,数据库里也没有。

    这样 Redis 就成了摆设,请求每次都直通数据库。这通常是代码 bug 或者黑客恶意攻击(一直请求 ID=-1 的数据)。

  • 解决方案

    1. 缓存空对象:数据库查不到,我也在 Redis 存一个null,并设个短一点的过期时间。下次你再来查 -1,Redis 直接告诉你“是空”,别烦数据库。

    2. 布隆过滤器 (Bloom Filter):在访问 Redis 之前加一道屏障。布隆过滤器能高效地判断“这个 ID 是否存在”。如果布隆说不存在,直接打回,连 Redis 都不用查。

  • 布隆过滤器原理分析:

如果说缓存空值是被动防御,那布隆过滤器就是主动拦截。

  • 核心原理: 底层是一个巨大的BitMap (位图)+N 个哈希函数

    • 存入时:经过 N 次 Hash 计算,将对应位置的比特位全部置为1

    • 查询时:同样的 N 次 Hash 计算,去查看对应位置。

  • 判定规则(铁律)

    • 只要有一位是 0:说明该 Key绝对不存在。 ->直接拦截,无需查库

    • 如果全都是 1:说明该 Key可能存在(存在极低概率是别的 Key 凑出来的 Hash 冲突)。 ->放行

3. 缓存雪崩 (Cache Avalanche) —— “全线崩塌”

同⼀时间⼤量key过期,导致查询全打到数据库上

最后一种情况,是规模最大的灾难。

  • 现象:

    大量的 Key 在同一时间集体过期,或者 Redis 节点直接宕机。

    这导致此刻所有的请求全部涌向数据库,数据库瞬间压力过大而崩溃。

  • 解决方案

    1. 打散过期时间:在设置 TTL 时,不要设成固定的 1 小时,而是TTL + 随机数(1-5分钟)。让 Key 排队过期,不要挤在一起。

    2. 高可用架构:利用 Redis Sentinel 或 Cluster,保证 Redis 挂了一个节点,其他的能立马顶上。

    3. 服务降级:当缓存和数据库都扛不住时,直接返回默认值或错误提示,保住系统不崩。


总结

Redis 的学习,不能只停留在命令的使用上。

  • 内存淘汰是为了让 Redis 永远只留最有价值的数据。

  • 击穿/穿透/雪崩的防御,是为了让 Redis 在面对流量洪峰和异常情况时,依然能稳稳地守护身后的数据库。

掌握了这些,你才算真正具备了驾驭大规模 Redis 集群的能力。下一篇,我们将深入 Redis 的集群架构,敬请期待!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 1:45:43

数据驱动测试:从缺陷探测到质量预见

测试数据的隐性价值 在敏捷开发与DevOps普及的当下,软件测试已从单纯的缺陷探测转向质量风险评估与预防。现代测试过程中产生的海量数据——包括用例执行记录、缺陷分布矩阵、性能基线对比、环境配置信息等——构成了评估产品质量态势的宝贵资产。据统计&#xff0…

作者头像 李华
网站建设 2026/7/7 6:57:06

告别“消失的小目标”:航拍图像检测新框架,精度飙升25.7%的秘诀

在人工智能迅猛发展的今天,目标检测作为机器视觉的核心任务,已经在自动驾驶、安防监控、工业质检等领域发挥着关键作用。然而,当我们把目光投向广阔的天空,面对航拍图像中密密麻麻的小目标时,传统检测方法却显得力不从…

作者头像 李华
网站建设 2026/7/3 14:00:41

2025年权威榜单荐选三款高品质动环监控系统,助你提升机房运维效率

在2025年,机房运维管理愈发重要,选择一款高品质的动环监控系统至关紧要。好的监控系统不仅能提供实时监控,确保设备正常运作,还能通过数据集成与报警功能帮助运维人员及时解决潜在问题。通过监测机房的环境因素如温湿度、火灾等&a…

作者头像 李华
网站建设 2026/7/7 7:57:58

MinGW64官网下载安装保姆级教程(附下载地址,非常详细)

MinGW-w64 是“Minimalist GNU for Windows 64-bit”的缩写,它把 Linux 下常见的 GCC、G、GDB 等一整套 GNU 开发工具搬到 Windows,让你不用装虚拟机就能在 Win 上直接编译 C/C 源码并生成 exe。 MinGW-w64 只依赖微软自带的 C 运行库,编译出…

作者头像 李华
网站建设 2026/7/7 10:05:04

文件io(Java版)

文章目录1. 文件操作和IO1.1java中操作文件1.2文件内容的读写--数据流InputStreamOutputStreamReaderWriter2.练习 对普通文件进行复制1. 文件操作和IO 1.1java中操作文件 Java中通过java.io.File类来对一个文件(包括目录)进行抽象的描述,有…

作者头像 李华
网站建设 2026/7/7 10:08:54

三相光伏并网Matlab/Simulink仿真:MPPT控制下的DC/DC与DC/AC并网逆变...

三相光伏并网Matlab/simulink仿真。 光伏采用MPPT控制以实现最大功率追踪。 DC/DC输入侧为光伏电池板,工作于最大功率跟踪模式,输入电压400V左右,功率等级30kW; DC/AC的DC侧750V,AC侧连接三相电网,相电压幅…

作者头像 李华