外观
碎片率 1.6 排查实录:Redis activedefrag 在线整理
问题背景:碎片率 1.6 背后的内存假象
凌晨告警显示某 Redis 实例 mem_fragmentation_ratio 长期维持在 1.6,used_memory_rss 比 used_memory 高出约 3GB。业务侧并没有写入等量新数据,容器却因为 RSS 逼近 maxmemory 触发了淘汰预警。这是典型的内存碎片问题:Redis 通过 jemalloc 申请的物理页没有归还给操作系统,逻辑上已释放的散碎空间无法被复用成连续块。
碎片率(RSS / used_memory)经验阈值如下:
- 1.0 ~ 1.2:健康;
- 1.2 ~ 1.5:可观察,关注写入模式;
1.5:需要介入,尤其伴随大 Value 频繁改写;
- < 1.0:内存被 swap 或部分 RSS 统计异常,风险反而更高。
需要强调:碎片率高不等于数据多,盲目扩容只会让账单上涨;直接重启虽能归还内存,却牺牲了可用性。正确路径是先定位碎片来源,再决定是否启用 activedegrag 在线整理。
方案对比:重启、MEMORY PURGE 还是 activedefrag
社区常见的三种处理手段各有边界:
| 方案 | 原理 | 优点 | 局限 |
|---|---|---|---|
| 滚动重启/主从切换 | 重建进程内存映像 | 碎片归零彻底 | 有闪断、冷启动、主从同步风险 |
MEMORY PURGE | 提示 jemalloc 回收脏页 | 执行简单 | 只对可归还的 arena 有效,无法移动活跃数据 |
activedefrag | 利用 jemalloc 活跃碎片整理,逐步搬迁 key | 在线、可控、无需切主 | 仅 Linux + jemalloc 编译版本有效,配置不当会抢占 CPU |
下图给出排查与治理的决策流程:
排查步骤:用 INFO 与大 Value 扫描定位根因
先确认内存口径与碎片趋势,避免只看单点值:
bash
# 连接 Redis 后查看关键指标
redis-cli -h 127.0.0.1 -p 6379 INFO memory重点字段含义:
text
used_memory:1073741824 # Redis 分配器视角的逻辑内存
used_memory_rss:1719664640 # 操作系统视角的常驻物理内存
mem_fragmentation_ratio:1.60 # RSS / used_memory
mem_fragmentation_bytes:645922816
allocator_active:1610000000 # jemalloc 已映射页
allocator_resident:1700000000随后排查大 Value。本例中一个用户画像 Hash 被反复全量覆盖,单个 key 超过 80MB,字段频繁增删导致大量不同尺寸的槽位无法复用。可使用离线扫描(不会阻塞主线程):
bash
# 离线模式扫描大 Key,生产建议在从节点执行并限速
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.1
# 查看某个可疑 key 的类型与占用字节
TYPE user:profile:10086
MEMORY USAGE user:profile:10086
HLEN user:profile:10086关键数据结构演示,复现“大 Hash + 频繁改写”的碎片制造过程:
bash
# 写入一个包含多个字段的 Hash(演示用,生产应拆分为小对象或分桶)
HSET user:profile:10086 name alice city beijing tag_v1 a tag_v2 b tag_v3 c
# 业务更新时不断增删不同字段,分配器容易留下空洞
HDEL user:profile:10086 tag_v1 tag_v2
HSET user:profile:10086 tag_long_version_2024 xxxxxxxxxxxxxxxxxxxx
EXPIRE user:profile:10086 86400
# 观察字段数与实际内存占用
HLEN user:profile:10086
MEMORY USAGE user:profile:10086
OBJECT ENCODING user:profile:10086治理大 Value 比单纯整理更关键:将超大 Hash 按业务维度拆成 user:profile:base:10086、user:profile:tag:10086,或改用分桶 Hash;过期时间加入随机抖动,避免同一秒海量 key 集中失效。否则碎片整理完成后还会再次累积。
在线整理:activedefrag 参数配置与验证
确认编译支持后再开启。activedefrag 依赖 jemalloc 的活跃碎片整理能力:
bash
# 必须返回 1,否则当前构建不支持
CONFIG GET activedefrag
# 先做一次轻量回收尝试
MEMORY PURGE若 PURGE 后碎片率仍高,可通过 CONFIG SET 动态开启,不需要重启:
bash
# 开启在线碎片整理
CONFIG SET activedefrag yes
# 触发门槛:碎片字节超过 100MB 且碎片率超过 1.1(保守起步)
CONFIG SET active-defrag-ignore-bytes 100mb
CONFIG SET active-defrag-threshold-lower 10
CONFIG SET active-defrag-threshold-upper 70
# CPU 占用上下限,生产环境先保守,再根据延迟调整
CONFIG SET active-defrag-cycle-min 1
CONFIG SET active-defrag-cycle-max 10
CONFIG SET active-defrag-max-scan-fields 1000参数含义要结合理解:阈值越低越早启动,cycle-max 越大整理越快但对主线程干扰越强;max-scan-fields 限制单次遍历 Hash/Set/Zset 元素数量,用来保护大 Value 场景。整理过程中可用以下命令持续验证:
bash
# 观察碎片字节、RSS 与整理是否在工作
INFO memory
INFO stats | grep -i active_defrag
# Redis 7 可查看整理相关指标(不同版本字段略有差异)
INFO stats期望现象是 active_defrag_hits、active_defrag_moves 等计数器增长,mem_fragmentation_bytes 逐步下降,RSS 缓慢回落,而 QPS、P99 延迟没有明显抖动。碎片降到合理区间后,可保留默认自动策略,也可在低峰结束后关闭:
bash
# 若只希望一次性整理,完成后关闭
CONFIG SET activedefrag no
# 验证运行态配置
CONFIG GET active-defrag-cycle-max注意 CONFIG SET 是运行态生效;若确认长期使用,需要同步写入 redis.conf 或部署模板,防止实例重启后配置丢失:
text
activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 70
active-defrag-cycle-min 1
active-defrag-cycle-max 10避坑总结:生产环境的 5 条具体注意事项
- 只看碎片率就开启整理,忽略大 Value 根因。现象是整理一周后碎片率再次回到 1.5 以上。修正方法:先用
--bigkeys、MEMORY USAGE定位被频繁覆盖的 Hash/List,拆分大对象、限制单 key 大小,再做碎片回收。 - 直接把
active-defrag-cycle-max调到 25 或更高。高峰时会出现 P99 延迟抬升、CPU steal 增加。修正方法:从 5~10 起步,结合latency latest和业务监控逐步调整,并优先在从节点或低峰窗口验证。 - 在不支持 jemalloc 的环境反复尝试。现象是
CONFIG SET activedefrag yes看似成功,但计数器长期不动。修正方法:通过INFO server的redis_version/redis_build_id与部署镜像确认编译选项,官方 Linux 版本通常启用 jemalloc,容器自编译镜像需显式检查。 - 把
MEMORY PURGE当成万能命令循环执行。它只能提示分配器回收干净的脏页,无法搬迁仍被 key 引用的散碎分配;高频执行收益有限。修正方法:将其作为诊断动作,真正的活跃碎片交给activedefrag,同时治理写入模式。 - 主从架构中只整理主节点或忽视复制影响。碎片是各进程独立形成的,从节点不会因为主节点整理而同步下降;搬迁过程还会消耗 CPU。修正方法:在从库优先验证参数,再通过故障切换或逐实例滚动处理,整理窗口避开全量同步与业务高峰。
内存碎片治理的核心不是“把数字压到 1.0”,而是在不牺牲延迟的前提下让 RSS 与真实数据量重新匹配。本次案例完成大 Value 拆分并开启保守版 activedefrag 后,碎片率在数小时内从 1.6 回落到 1.15 附近,回收约 2.7GB RSS,期间未出现明显延迟尖峰。
免责声明
本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。