Redis从节点的内存碎片问题是一个容易被忽视的细节——它不会自动继承主节点的配置,必须为每个节点单独设置才能生效。否则,即使主节点的碎片率已经降低,从节点仍可能持续膨胀,直到 mem_fragmentation_ratio 超过 2.0 才停止。

核心结论: 从节点的内存碎片不会自动跟随主节点,必须逐个节点单独配置并生效。否则,即使主节点碎片率已下降,从节点仍可能持续攀升至 mem_fragmentation_ratio > 2.0。
为什么从节点容易被忽略?
在 Redis Cluster 或哨兵模式下,CONFIG SET 命令仅对当前连接的节点生效,且不会持久化。运维人员常常只在主节点执行 CONFIG SET activedefrag yes,但忽略了从节点——其配置仍停留在默认值:active-defrag-threshold-lower 为 10(即 10%),active-defrag-cycle-min 仅为 5,实际效果近乎关闭。
- 从节点既要承担读流量,又要应对复制压力,CPU 本就紧张,碎片整理任务更难获得时间片。
- 复制过程中,大量小对象频繁写入(例如 AOF rewrite 后的 bulk load),会加剧 jemalloc 的页内碎片问题。
- 通过
INFO memory查看,从节点上的active_defrag_running长期显示为 0,但mem_fragmentation_ratio却在缓慢上升,却无任何整理动作。
从节点必须显式设置的四个参数
不要以为只开启 activedefrag yes 就够了——那几乎等于没开。以下四个参数必须同时写入每个从节点的 redis.conf,然后重启(或通过 CONFIG REWRITE + CONFIG SET 双重确认):
activedefrag yes:总开关,必须明确写为yes(不是on或1)。active-defrag-ignore-bytes 100mb:避免小碎片反复触发整理;低于此阈值直接跳过,减少无效操作。active-defrag-threshold-lower 12:注意单位是“占used_memory_rss的百分比 ×10”,填写12表示 ≥12% 时才启动(比默认的10更敏感)。active-defrag-cycle-min 100和active-defrag-cycle-max 500:提高单次整理时长上限,弥补从节点 CPU 空闲时间较少的短板。
验证从节点是否真正在整理
不要只看 CONFIG GET activedefrag 返回 yes 就认为万事大吉。真正需要关注的是运行时状态:
- 执行
redis-cli -h sla ve-ip -p port INFO memory | grep -E "(mem_fragmentation_ratio|active_defrag)"。 - 确认
active_defrag_running:1偶尔出现——不是持续为 1,而是间歇性为 1,表明系统确实在执行整理。 - 观察
active_defrag_hits是否随时间缓慢增长;如果 10 分钟内保持不变,说明尚未触发。 - 对比
used_memory_rss与used_memory的差值:若从 3GB 逐渐降至 2.2GB,说明整理生效。
容易踩的坑:jemalloc 版本与 MEMORY PURGE 无效
即使所有 activedefrag 参数都配置正确,从节点也可能毫无反应——最容易被忽略的前提条件是:
redis-cli INFO memory | grep mem_allocator必须返回jemalloc;如果是libc,则activedefrag完全不工作(MEMORY PURGE同样无效)。- 某些容器镜像或编译安装版本默认使用了
libc,需要重新编译 Redis 并指定--with-jemalloc。 MEMORY PURGE命令仅对 jemalloc 生效,且只释放“脏页”,无法合并已分配页内的空隙——它不能替代activedefrag,只能作为辅助手段。- 集群滚动升级时,新部署的从节点若未同步
redis.conf中全部的active-defrag-*行,就会悄然成为“碎片黑洞”。
真正起效的关键,不在于参数写得多么华丽,而在于每个从节点的 redis.conf 中,是否完整、显式、持久地包含了那四行 active-defrag-* 配置——少一行,碎片率就可能卡在 1.8 不动,白白浪费资源。
