内存碎片率≥1.8说明碎片严重,<1则已启用swap导致卡顿;主动碎片整理需同时满足碎片量>100MB且碎片率>10%才触发,定时CONFIG SET无效,Redis 6.2+需用MEMORY PURGE强制释放。

怎么判断内存碎片率真高了?别光看数字
直接跑命令:redis-cli INFO MEMORY | grep "mem_fragmentation_ratio"。如果结果是 1.8 或更高,说明操作系统给 Redis 分了 1.8 倍于它实际用的物理内存——空闲但没法用的“碎渣”已经堆积不少了。注意:mem_fragmentation_ratio 是更危险的信号,代表 Redis 内存不够用了,开始动 swap,响应会明显卡顿。
为什么定时触发清理不等于“自动清”?关键看两个阈值
Redis 的主动碎片整理(active defrag)不是常驻后台线程,而是按需抽查式工作。它只在满足两个条件时才真正干活:active-defrag-ignore-bytes(默认 100MB)和 active-defrag-threshold-lower(默认 10%)。意思是:当前碎片总量超过 100MB,且碎片率高于 10%,才会启动扫描;一旦任一条件不满足,立刻停手。
- 所以单纯设个 cron 每小时跑一次
CONFIG SET active-defrag yes没用——这个配置只是开关,不触发动作 - 真正要“闲时定时触发”,得靠
MEMORY PURGE命令(Redis 6.2+),它强制让分配器把能还的内存还给系统,但只对 jemalloc/tcmalloc 有效 - 老版本(MEMORY PURGE,只能靠重启或等自然回收,定时脚本意义不大
怎么写一个靠谱的闲时清理脚本?别在高峰期硬来
碎片整理本身要扫描内存页、搬运数据,会短暂升高 CPU 和延迟。所以必须避开业务高峰,也得确认 Redis 正在用支持 defrag 的分配器(INFO MEMORY 里看 mem_allocator 是不是 jemalloc)。
- 先检查是否就绪:
redis-cli INFO MEMORY | grep -E "(mem_fragmentation_ratio|mem_allocator)" - 再判断是否值得清:
redis-cli --raw MEMORY USAGE some_hot_key看大 key 是否集中,避免“小碎片大开销” - 定时任务示例(每天凌晨 2 点):
0 2 * * * redis-cli CONFIG SET active-defrag yes && sleep 1 && redis-cli MEMORY PURGE
- 加
sleep 1是因为CONFIG SET异步生效,立刻跟MEMORY PURGE可能被忽略
容易被忽略的坑:UNLINK 比 DEL 更治标,但不是万能解药
日常删键时用 UNLINK 替代 DEL,能让删除操作立刻返回,释放逻辑交给后台线程异步做,减少阻塞。但它只影响“刚删的键”的内存归还节奏,对已存在的历史碎片无效。
-
UNLINK对小 key 效果有限,对大 hash/list/zset 才明显 - 如果碎片主因是频繁改写(比如 value 从 1KB 被改成 100KB),旧内存块仍留在那里,
UNLINK不管这事 - 真正顽固的外部碎片,最终还得靠
MEMORY PURGE或换用 tcmalloc(比 jemalloc 更激进归还)
碎片不是 bug,是内存分配器权衡性能换来的代价。能压到 1.3 以内就不错了,强求 1.0 往往意味着频繁申请释放,反而伤性能。











