bigywater.tech
Redis · 111

Redis Active Defrag

这篇有一个遗憾要先说:Active Defrag(主动碎片整理)只在特制的 jemalloc 构建上可用,我这台机器上的 Redis 用的是 libc,开启会直接失败——所以我没法演示「整理」本身。能演示、并且值得演示的是它要解决的问题:碎片是怎么产生的,有多严重。这部分是完整实测的。

libc,不是 jemalloc
activedefrag 在本机构建上不能启用,CONFIG SET 报错
171 → 18 MB
随机删除 90% 的 key:used_memory 的变化
180 → 189 MB
同一过程 used_memory_rss(操作系统眼中的占用)几乎没变

先看分配器

实测 · 本机执行输出
  mem_allocator = libc

INFO memory 里的 mem_allocator 是 libc。Redis 官方源码自带并默认使用的是定制的 jemalloc;Homebrew 这个构建用了系统的 libc malloc。

开启 activedefrag

实测 · 本机执行输出
> CONFIG SET activedefrag yes
(error) ERR CONFIG SET failed (possibly related to argument 'activedefrag') - Active defragmentation cannot be enabled: it requires a Redis server compiled with a modified Jemalloc like the one shipped by default with the Redis source distribution
> MEMORY PURGE
"OK"

报错原文:Active defragmentation cannot be enabled: it requires a Redis server compiled with a modified Jemalloc like the one shipped by default with the Redis source distribution。所以「主动碎片整理有多有效」这个问题,本文没有答案;需要在 jemalloc 构建(比如官方 Docker 镜像)上测。我这台机器上 Docker 没有运行,没法补上。

碎片是怎么来的

100 万个 key,value 20–199 字节随机;然后随机删除 90%
实测 · 本机执行输出
  写入 100 万个 key 后            used_memory=  171.3 MB  used_memory_rss=  180.2 MB  mem_fragmentation_ratio=1.10  allocator_frag_ratio=1.00
  随机删除 90% 之后                used_memory=   18.2 MB  used_memory_rss=  188.8 MB  mem_fragmentation_ratio=10.38  allocator_frag_ratio=1.00
  used_memory 从 171 MB 降到 18 MB(-89%);used_memory_rss 从 180 MB 到 189 MB(--5%)

写入完成时 used_memory 171 MB、used_memory_rss 180 MB,碎片率 1.10。随机删掉 90% 的 key 之后 used_memory(Redis 自己统计的已分配)降到 18 MB,但 used_memory_rss 仍是 189 MB——碎片率 10.38。原因:被删除的 key 散落在整个堆里,每个大块里都还夹着仍然存活的 key,分配器无法把整块还给系统。(这里是 libc 分配器 + macOS;jemalloc 上的表现会不同,我没有测。)

MEMORY PURGE 与 MEMORY DOCTOR

实测 · 本机执行输出
  Sam, I detected a few issues in this Redis instance memory implants:   * Peak memory: In the past this instance used more than 150% the memory that is currently using. The allocator is normally not able to release memory after a peak, so you can expect to see a big fragmentation ratio, however this 

MEMORY PURGE 让分配器尝试归还内存,在 libc 上返回 OK 但没有可见效果。MEMORY DOCTOR 给出的诊断对应「峰值之后分配器通常无法释放内存」——它没有说这是「碎片」,而是「峰值」;两者在这个实验里其实是同一件事的两种说法。

这个指标怎么读

mem_fragmentation_ratio = RSS ÷ used_memory。远大于 1 表示「进程占着系统的内存,但 Redis 自己已经没在用」;小于 1 则通常意味着发生了 swap。它不等于「可以回收」:回收要靠 active defrag(需要 jemalloc)、重启,或者让新数据重新利用这些空洞。本文只验证了「这个比值会变得很高」,没有验证「怎么降下来」。

分步演示:碎片的来历

Redis Active Defrag
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。Homebrew 构建,mem_allocator=libc;value 长度 20–199 字节随机(random.Random(4));删除是随机选 90% 的 key
    • 没有验证:activedefrag 本身的效果与开销(需要 jemalloc)、jemalloc 上的碎片形态、MEMORY PURGE 在 jemalloc 上的效果、Linux 上 RSS 的表现、overcommit 与 THP 对碎片的影响
    京ICP备2026067502号-1京公网安备11010502063487号