Redis 内存回收

一、Redis 内存回收的整体架构

Redis 是一个 内存数据库 ,所有键值都存放在 RAM 中。

为了避免无限增长导致 OOM(Out Of Memory),Redis 有三大类内存回收机制:

1. 键过期删除策略(主动回收)

  • 惰性删除(Lazy Deletion)
  • 定期删除(Tuned Scanning)

2. 内存淘汰策略(当内存达到最大值 maxmemory)

  • noeviction / allkeys-* / volatile-* 系列

3. 内存碎片与 jemalloc 管理(内存再利用)

  • jemalloc arena 管理
  • active defrag(主动碎片整理)

这三者共同对 Redis 内存进行回收和优化。


二、键过期删除(Expires)

Redis 支持给 key 设置 TTL(time-to-live)。

复制代码
EXPIRE key 10
SET key value EX 10

Redis 的过期键删除不是精确实时触发,而是采用三种机制组合:


1. 惰性删除(Lazy Deletion)

触发时机:

  • 当客户端访问某个 key
  • Redis 检查它是否已经过期
  • 过期 → 立即删除

示例:

复制代码
GET key
→ 发现 key 已过期 → 删除并返回 nil

优点:

  • 简单、高效
  • 不访问不过期,不浪费 CPU

缺点:

  • 如果 key 很久不被访问
  • 会一直占用内存(内存泄漏风险)

所以 Redis 还必须搭配第二种机制。


2. 定期删除(Active Expire Cycle)

Redis 每 100ms(server.hz 参数控制)随机抽取部分带过期时间的 key:

流程:

  1. 随机扫描一部分 db.expires 字典
  2. 删除其中已经过期的 key
  3. 如果过期比例 > 25%,继续扫描(最多执行 25ms)

优点:

  • 避免过期键长期堆积
  • 平衡 CPU 占用

缺点:

  • 不是实时、高精度的删除
  • 大量过期键可能延迟删除

3. 主动删除 + 从节点同步

在执行命令期间,如果命令涉及访问过期 key:

  • 主线程执行惰性删除
  • 命令传播到从节点和 AOF 时也写入 DEL 操作

三、内存淘汰策略(maxmemory 触发)

当 Redis 达到 maxmemory 时,就会触发内存淘汰策略。

配置:

复制代码
maxmemory 2gb
maxmemory-policy allkeys-lru

Redis 内置 8 种策略:


1. 不淘汰

● noeviction

内存满时写命令(SET/LPUSH/ZADD)直接报错。


2. 只淘汰带过期时间的键(volatile-*)

策略 说明
volatile-lru 淘汰最近最少使用的 expire key
volatile-lfu 淘汰访问最少的 expire key
volatile-ttl 淘汰剩余生存时间最短的 key
volatile-random 随机淘汰一个 expire key

如果没有带 TTL 的 key → 和 noeviction 一样报错。


3. 淘汰所有键(allkeys-*)

策略 说明
allkeys-lru 淘汰最近最少使用的 key
allkeys-lfu 淘汰访问最少的 key(Redis 4+)
allkeys-random 随机淘汰一个 key

企业生产最常用:

复制代码
allkeys-lru
allkeys-lfu(访问热点分布更均衡)

四、Redis 的内存分配器:jemalloc

Redis 默认使用 jemalloc 来管理内存。

jemalloc 特点:

  • 多个 arena,减少锁竞争
  • 对小块内存管理更高效
  • 减少内存碎片
  • 速度快(Redis 高性能关键之一)

Redis 里每个 key/结构体 要走 jemalloc 的分配逻辑。


四、内存碎片问题

Redis 内存碎片率:

复制代码
info memory → mem_fragmentation_ratio

当碎片率 > 1.5 或 2 时可能需要处理。

Redis 支持主动碎片整理:

复制代码
active-defrag yes

作用:

  • 后台线程合并碎片块
  • 迁移 key 的内存布局
  • 减少物理内存占用

适用于高更新写 load 的业务。


五、Redis 内存回收的整体流程图


六、实际场景中的内存回收案例

情况 1:大量 key 同时过期(如 0 点定时刷新)

效果:

  • 惰性删除无法及时回收
  • 定期扫描也跟不上
  • Redis 内存激增

解决:

  • 设置随机 TTL(打散过期时间)
  • 使用 expire 命令 + 随机偏移

情况 2:大量数据更新导致碎片暴涨

解决:

复制代码
active-defrag yes

适合 key 更新频繁的系统(订单系统、排行榜系统)。


情况 3:内存爆满导致频繁淘汰、QPS 急剧下降

解决:

  • 分析 key 大小(大 key 拆分)
  • 调整 maxmemory-policy
  • 提高 Redis 内存
  • 使用 Redis Cluster 分片

七、面试高频问题(含标准答案)

1. Redis 的过期删除策略是什么?

答:惰性删除 + 定期删除 双策略。


2. Redis 内存淘汰策略有哪些?

8 种:

  • noeviction
  • volatile-lru / lfu / ttl / random
  • allkeys-lru / lfu / random

3. 为什么 Redis 采用定期删除而不是主动删除?

因为主动删除是 O(n) 扫描,会阻塞主线程。


4. LRU 与 LFU 区别?

  • LRU:最近最少使用
  • LFU:访问次数最少

LFU 更适合热点数据分布不均的业务。


5. Redis 为什么使用 jemalloc?

  • 更快
  • 内存碎片更少
  • 多线程 arena 更适合 Redis 高并发

6. active-defrag 是如何工作的?

后台线程迁移 key 内部结构,使碎片合并。


八、总结(背诵版)

Redis 内存回收 = 过期清理 + 内存淘汰 + 内存碎片整理

  • 过期键:惰性删除 + 定期删除
  • 内存限制:maxmemory-policy
  • 内存管理:jemalloc
  • 碎片修复:active-defrag
  • 大 key 问题:拆分 + 批量删除

Redis 内存管理体系既高效又安全,是持久高性能的重要基础。

相关推荐
七夜zippoe17 小时前
缓存策略:从本地到分布式架构设计与Python实战
分布式·python·缓存·lfu·lru
江上月51317 小时前
JMeter中级指南:从数据提取到断言校验全流程掌握
java·前端·数据库
晨旭缘17 小时前
零基础后端入门:JDK21 + PostgreSQL+Java项目
java·数据库·postgresql
萧曵 丶17 小时前
MySQL InnoDB 实现 MVCC 原理
数据库·mysql·mvcc
ss27317 小时前
ruoyi 新增每页分页条数
java·数据库·mybatis
oMcLin17 小时前
如何在 Debian 10 上通过配置 Redis 集群的持久化选项,提升高可用性缓存系统的容错性与性能?
redis·缓存·debian
万粉变现经纪人17 小时前
如何解决 pip install mysqlclient 报错 ‘mysql_config’ not found 问题
数据库·python·mysql·pycharm·bug·pandas·pip
lkbhua莱克瓦2417 小时前
进阶-SQL优化
java·数据库·sql·mysql·oracle
石小千17 小时前
Myql binlog反向解析成sql
数据库·sql
alonewolf_9917 小时前
MySQL 8.0 主从复制原理深度剖析与实战全解(异步、半同步、GTID、MGR)
数据库·mysql·adb