activedefrag与maxmemory-policy是两套独立机制,前者整理内存分配器碎片,后者淘汰键空间数据,互不触发、不协同;开启activedefrag仅缓解RSS虚高导致的“假性淘汰”,无法替代真实内存超限时的淘汰逻辑。

activedefrag 和 maxmemory-policy 是两套独立机制,不自动协同
Redis 7.0 中 activedefrag 和内存淘汰策略(如 allkeys-lru)各自运行在不同逻辑层:前者是内存分配器(jemalloc)层面的空间整理,后者是 Redis 键空间层面的逻辑删除。它们不会互相触发、也不会共享阈值判断——开启 activedefrag yes 不会让淘汰变少,设成 noeviction 也不会阻止碎片整理启动。
常见误解是“开了碎片整理,淘汰就少了”,实际只是间接效果:整理后 used_memory_rss 下降,mem_fragmentation_ratio 回落,从而延缓因 RSS 虚高导致的“假性超限”——但只要 used_memory 真实突破 maxmemory,淘汰照样触发。
-
activedefrag只在 CPU 空闲时运行(active_defrag_running为 1 才算真干活),而高负载下淘汰可能正密集发生,两者常处于“错峰”状态 - 淘汰释放的内存块是否能被
activedefrag合并,取决于 jemalloc 的分配策略和块大小分布,不是淘汰完就自动整理 - 若用
volatile-random策略高频删小 key,释放大量离散小块,activedefrag整理效率会明显下降
内存淘汰频繁时,先看是不是碎片假性超限
执行 INFO memory 后发现 evicted_keys 持续增长,但 used_memory 远低于 maxmemory,同时 mem_fragmentation_ratio > 1.5 且 used_memory_rss - used_memory > 100mb,基本可断定是碎片导致的“误淘汰”。
这时调优淘汰策略(比如从 volatile-lru 改成 allkeys-lru)作用有限,真正要做的三件事:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 确认
mem_allocator是jemalloc(非libc),否则activedefrag直接无效 - 检查四个硬性条件是否齐备:
activedefrag yes、active-defrag-ignore-bytes 100mb、active-defrag-threshold-lower 10、active-defrag-cycle-min 25 - 手动触发一次
MEMORY PURGE(仅 jemalloc 支持),快速回收已释放但未归还 OS 的页
listpack 编码能降低碎片源头,但不改变淘汰触发逻辑
Redis 7.0 默认用 listpack 替代 ziplist,让小对象内存布局更规整,减少 jemalloc 内部碎片。实测中相同数据量下 mem_fragmentation_ratio 可从 1.6+ 压到 1.2 左右——但这只是推迟了淘汰时间点,不是取消淘汰。
关键点在于:即使用了 listpack,只要业务持续写入新 key 或扩大已有结构(如 HSET 字段数超 hash-max-ziplist-entries),仍会退化为 hashtable 或 quicklist,碎片照常产生。
- 用
DEBUG OBJECT key验证编码是否生效,返回encoding: listpack才算成功 -
hash-max-ziplist-entries设太小(如 16)会导致哈希表频繁升级,反而加剧碎片 - 高频
LPOP+RPUSH边界操作会反复 realloc,把连续listpack拆成多段,失去紧凑优势
真正协同的关键动作:监控指标联动判断
不要单独盯 evicted_keys 或 mem_fragmentation_ratio,必须交叉看:
-
evicted_keys增速快 +expired_keys增速慢 → 淘汰主因是内存压力,而非过期集中爆发 -
active_defrag_running长期为 0 → 不是配置没开,而是 CPU 满载或碎片总量未达标(used_memory_rss - used_memory < 100mb) -
mem_allocator显示libc→ 即使所有参数配对,activedefrag也完全不工作
最易被忽略的是:碎片整理本身不解决“键太多占满内存”的问题,它只解决“内存明明有空,却报 OOM”的错觉。当 used_memory 真实逼近 maxmemory,再好的碎片整理也救不了——该扩容还是得扩容,该清理冷数据还是得清理。

















