[踩坑] Redis 内存碎片问题深度解析与解决方案
在 Redis 运维过程中,你是否遇到过这样的困惑:明明已经删除了大量数据,used_memory 也确实下降了,但服务器的实际内存占用却几乎没有变化?
这就是 Redis 内存碎片问题,也是生产环境中最常见、最容易被忽视的性能隐患之一。本文将从原理到实战,全面解析 Redis 内存碎片的成因、诊断方法和解决方案。
一、什么是内存碎片?
1.1 内存分配原理
Redis 并不直接使用操作系统的 malloc,而是使用专门的内存分配器(默认为 jemalloc)。内存分配器为了提高效率,会按固定大小的块来分配内存,例如:
申请 10 bytes → 实际分配 16 bytes |
多出来的部分就是内部碎片。
1.2 碎片是如何产生的
初始状态: |
这就是外部碎片——内存空间存在,但因为不连续而无法被利用。
二、真实案例分析
以下是一个生产环境中的实际数据:
# 执行 MEMORY PURGE 前 |
结论: 数据只用了 10.54G,但系统实际占用 22.71G,约 12G 内存被碎片浪费。
三、核心指标解读
3.1 关键字段说明
| 字段 | 含义 |
|---|---|
used_memory | Redis 分配器认为已使用的内存 |
used_memory_rss | 操作系统视角的实际物理内存占用 |
used_memory_peak | 历史内存峰值 |
mem_fragmentation_ratio | 内存碎片率 = rss / used_memory |
active_defrag_running | 自动碎片整理是否正在运行(1=是) |
3.2 碎片率健康标准
mem_fragmentation_ratio < 1.0 → 内存不足,可能使用了 Swap(危险) |
四、碎片产生的常见原因
4.1 大量删除操作
频繁 DEL、EXPIRE 过期 key,留下大量不连续的空洞。
4.2 Value 大小变化频繁
# 先写入小 value |
原来的空间不够用,分配器重新分配,旧空间变成碎片。
4.3 使用了不合适的数据结构
- 大量小 String 替代 Hash → 碎片率更高
- ziplist 升级为 hashtable 后旧内存未释放
4.4 jemalloc 版本较旧
旧版 jemalloc(如 4.0.3)碎片整理能力较弱,建议升级 Redis 版本。
五、诊断方法
5.1 查看内存信息
# 查看完整内存信息 |
5.2 查看 key 分布
# 查看总 key 数量 |
5.3 内存使用分析
# 查看指定 key 内存占用 |
六、解决方案
6.1 方案一:手动触发整理(快速见效)
# 立即释放碎片内存 |
优点: 立即执行,效果明显
缺点: 一次性操作,不能持续整理,可能短暂影响性能
6.2 方案二:开启自动碎片整理(推荐)
# 动态开启,无需重启 |
写入配置文件永久生效:
# redis.conf |
验证是否在运行:
redis-cli INFO memory | grep active_defrag_running |
6.3 方案三:重启 Redis(最彻底)
# 第一步:持久化数据 |
⚠️ 重启会造成短暂服务中断,生产环境建议在低峰期操作,或使用主从切换方式滚动重启。
6.4 方案四:主从切换滚动重启(生产推荐)
# 1. 对从节点执行重启 |
七、预防措施
7.1 合理设置淘汰策略
# 当前危险配置 |
| 策略 | 适用场景 |
|---|---|
noeviction | 数据不能丢失,需要严格控制 key 数量 |
allkeys-lru | 缓存场景,允许自动淘汰 ⭐ |
volatile-lru | 只淘汰有过期时间的 key |
allkeys-random | 随机淘汰,不推荐 |
7.2 为 key 设置过期时间
# 避免永久 key 堆积 |
7.3 使用合适的数据结构
# 不推荐:大量小 String |
7.4 监控告警
# 写入监控脚本 |
八、操作流程总结
发现碎片率高(> 1.5) |
九、常见问题 FAQ
Q:开启 activedefrag 会影响性能吗?
会有轻微影响,但通过 active-defrag-cycle-max 25 限制 CPU 占用在 25% 以内,生产环境基本无感知。
Q:used_memory 和 used_memory_rss 哪个是真实占用?
used_memory_rss 是操作系统视角的真实物理内存占用,是更准确的参考值。
Q:为什么重启后碎片率会降为 1.0 左右?
重启后 Redis 重新加载 RDB/AOF 数据,内存重新分配,碎片全部消除,是最彻底的整理方式。
Q:jemalloc 和 libc 哪个碎片率更低?
jemalloc 的碎片控制能力优于 libc,Redis 默认使用 jemalloc,无需更换。
十、总结
| 方案 | 效果 | 风险 | 适用场景 |
|---|---|---|---|
| MEMORY PURGE | 中等 | 低 | 临时快速处理 |
| activedefrag | 持续 | 极低 | 生产长期运行 ⭐ |
| 重启 Redis | 彻底 | 中 | 低峰期维护 |
| 主从滚动重启 | 彻底 | 低 | 高可用生产环境 ⭐ |
Redis 内存碎片是不可避免的,关键在于持续监控 + 自动整理 + 合理配置,将碎片率长期控制在 1.5 以内,才能保证 Redis 稳定高效运行。
参考资料
- Redis 官方文档 - Memory Optimization
- Redis CONFIG SET activedefrag
- jemalloc 内存分配器文档
redis-cli INFO memory命令手册



