Redis 内存碎片是什么?如何排查和优化?
简化版
Redis 内存碎片是分配器向操作系统申请的内存大于 Redis 实际存放数据需要的内存,常由频繁增删改、大 Key 变化、分配器复用不充分导致。排查看 INFO memory 的 mem_fragmentation_ratio、RSS、used_memory,并结合 bigkey、淘汰策略和主动碎片整理优化。
详细版
Redis 内存指标常见有:
used_memory:Redis 数据和内部结构使用的内存。used_memory_rss:进程实际占用的物理内存。mem_fragmentation_ratio:RSS 与 used_memory 的比例。
碎片率过高说明 Redis 进程占用内存明显高于数据实际使用。原因可能是频繁写入删除、value 大小变化大、大 Key 删除、jemalloc 分配粒度、fork 写时复制等。
优化方向包括拆 BigKey、稳定 value 大小、合理 maxmemory、开启主动碎片整理、低峰期执行清理、避免短时间大批量删除。不能只看一个 ratio,要结合实例大小和操作系统内存判断。
完整版教学
一、内存碎片到底是什么
内存碎片可以理解为“房间租了很多,但真正放东西的面积没那么多”。Redis 通过内存分配器申请和释放内存,释放后的空间不一定马上还给操作系统,也不一定正好能被下一次分配复用。
如果 used_memory 是 4 GB,而 used_memory_rss 是 6 GB,碎片率大约是 1.5。多出来的 2 GB 不一定是业务数据,可能是碎片、分配器保留、进程额外开销。
记忆钩子:used_memory 看“东西有多少”,RSS 看“房子占多少”,碎片看“房子和东西差多少”。
二、关键指标怎么看
INFO memory 是排查入口。核心指标包括 used_memory、used_memory_rss、mem_fragmentation_ratio、allocator_frag_ratio、allocator_rss_ratio 等。
used_memory = 4GB
used_memory_rss = 6GB
mem_fragmentation_ratio = 6 / 4 = 1.5
但 ratio 要结合绝对值看。一个很小的实例 used_memory 只有 20 MB,RSS 60 MB,ratio 是 3,也未必严重;一个 100 GB 实例 ratio 1.3,多出来 30 GB 就很危险。
三、为什么频繁增删改会产生碎片
Redis value 大小经常变化时,旧内存块释放,新内存块申请,分配器可能留下很多大小不合适的空洞。例如一个 key 的 value 在 1 KB、20 KB、3 KB 之间反复变化,复用效率就可能下降。
BigKey 删除也会制造明显波动。一个包含百万 field 的 Hash 被删除,释放过程和分配器回收都可能带来延迟和碎片。
写入 20KB -> 删除 -> 空出 20KB 块
写入 3KB -> 可能只复用一部分
剩余空间 -> 碎片或等待复用
四、maxmemory 和碎片的关系
Redis 的 maxmemory 控制的是 Redis 视角的内存使用,不一定等于进程 RSS。碎片率高时,即使 used_memory 没超过 maxmemory,操作系统层面的物理内存也可能紧张。
比如机器 16 GB,Redis maxmemory 设置 12 GB,碎片率 1.4 时 RSS 可能接近 16.8 GB,系统就可能发生 swap 或 OOM 风险。
| 指标 | 示例 |
|---|---|
| maxmemory | 12 GB |
| used_memory | 12 GB |
| fragmentation ratio | 1.4 |
| 估算 RSS | 16.8 GB |
所以容量规划要给碎片、fork、客户端缓冲区和系统留余量。
五、主动碎片整理能解决什么
Redis 支持主动碎片整理,尝试把分散对象搬到更紧凑的内存位置,让分配器释放更多页。它能降低部分碎片,但会消耗 CPU。
这类优化应该压测和灰度。业务高峰期激进整理可能带来 CPU 抖动,低峰期逐步整理更稳。碎片整理不是替代数据模型优化的银弹。
先监控 -> 判断碎片绝对量 -> 低峰开启/调参 -> 观察 CPU 与 P99
六、从数据模型减少碎片
比起事后整理,更好的方式是减少碎片来源。常见做法包括拆分 BigKey、控制 value 大小、避免频繁重写大对象、批量删除改成渐进式删除。
例如把一个 100 万 field 的 Hash 按用户段拆成 100 个小 Hash,删除、迁移、过期和复制压力都会更可控。碎片问题往往和 BigKey 治理相互关联。
| 问题 | 改法 |
|---|---|
| 大 Hash 频繁改 | 分片拆 key |
| 大量一次性删除 | 分批删除或异步删除 |
| value 大小剧烈变化 | 稳定结构或拆冷热字段 |
七、排查流程怎么讲
线上排查不要只盯 mem_fragmentation_ratio。建议按实例内存、RSS、碎片绝对值、BigKey、fork、淘汰、客户端缓冲区一起看。
INFO memory
|
看 used_memory / RSS / ratio
|
查 BigKey 与写入删除模式
|
看 fork/AOF rewrite/复制
|
决定拆 key、调 maxmemory、开碎片整理或迁移重启
有时重启可以降低碎片,但它是运维手段,不是根因修复。面试回答要体现你会找根因。
八、常见误区与追问
- 误区:碎片率大于 1 就一定有问题。 要结合 used_memory 规模和 RSS 绝对差值判断。
- 误区:maxmemory 设置好了就不会 OOM。 RSS、fork 写时复制、客户端缓冲区都可能额外占内存。
- 误区:重启 Redis 就算解决碎片。 重启可能短期下降,但频繁增删大对象的根因仍在。
- 追问:碎片整理会不会影响性能? 会消耗 CPU,需低峰、灰度、观察 P99。
- 追问:BigKey 和碎片有什么关系? 大对象分配释放不均衡,容易放大碎片和释放延迟。
- 追问:怎么给 maxmemory 留余量? 根据碎片率、fork 峰值、连接缓冲区和系统内存预留,而不是贴满机器内存。
九、加强记忆
记住“used_memory 是数据,RSS 是占用,ratio 是差距”。碎片问题本质是内存分配和释放不均衡带来的空间浪费。
答题时按指标、原因、风险、治理四步走:看 INFO memory,找 BigKey 和写删模式,再决定整理、拆分、限额或迁移。