redis内存泄漏需通过memory stats和info memory指标变化确认:当dataset.bytes稳定而overhead.total和total.allocated持续上涨,且evicted_keys为0、expired_keys增速正常时,基本可判定为泄漏;需优先排除clients.normal或replication.buffer异常占用。

Redis 内存泄漏不能靠“感觉”判断,必须盯住 MEMORY STATS 和 INFO memory 里几个具体字段的持续变化趋势——尤其当 dataset.bytes 不涨而 total.allocated 涨个不停时,基本就是泄漏了。
怎么确认不是误报:先排除客户端缓冲区积压
很多所谓“内存泄漏”其实是客户端读太慢,导致 Redis 在内存里堆着发不出去的数据。重点看 MEMORY STATS 输出里的:
-
clients.normal:普通客户端输出缓冲区总大小,单个连接超 10MB 就该查了 -
replication.buffer:从节点同步卡住时会暴涨,INFO replication中master_link_status:down或sync_in_progress:1是佐证 - 如果这两项占了
total.allocated的 60% 以上,先优化客户端消费速度或调大client-output-buffer-limit,别急着查代码
真正泄漏的信号:dataset.bytes 不动但 overhead.total 持续爬升
dataset.bytes 是你存进去的实际数据体积,overhead.total 是 Redis 自身管理开销(dict 表、链表指针、对象头等)。正常业务下两者应同向波动。泄漏典型表现是:
- 业务写入量稳定,
dataset.bytes几小时几乎不变(比如始终在 2.1GB ± 50MB) - 但
overhead.total从 300MB 涨到 800MB,且total.allocated同步上涨 - 同时
evicted_keys为 0、expired_keys增速正常,说明没触发淘汰,也不是 Key 过期堆积
这时大概率是模块级资源未释放,比如 Lua 脚本里用 redis.call("set", ...) 创建了临时 key 却没 del,或某些 client 库反复新建 connection pool 但没 close。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
用 INFO memory 快速定位泄漏源头
INFO memory 比 MEMORY STATS 更轻量,适合高频采集。重点关注这三组值的比值关系:
-
used_memory/used_memory_human:当前实际使用量,单位要统一(避免 KB vs MB 混淆) -
mem_fragmentation_ratio:若 > 1.5 且allocator.rss远大于used_memory,优先怀疑内存碎片而非泄漏——此时重启实例可能比查代码更有效 -
used_memory_peak-used_memory:差值长期 > 500MB,说明有大量对象被分配后没被回收,结合redis-cli --bigkeys扫描大对象,再用MEMORY USAGE精确到 key 级
监控配置容易漏掉的关键点
用 Prometheus + redis_exporter 时,以下三项不配好,指标就等于没接:
- Redis 配置里必须设
maxmemory,否则redis_memory_max_bytes为 0,所有内存使用率计算失效 - Exporter 连接要用带密码的 URL 格式:
redis://:password@127.0.0.1:6379,明文密码不加:会被静默忽略 - 低版本 Redis(protected-mode yes 时,必须显式配置
bind 0.0.0.0或requirepass,否则 exporter 连不上,metrics 里连redis_up都是 0
真正难的不是发现泄漏,而是区分它是来自 Redis 自身(如旧版 cluster slot 缓存未清理)、客户端 SDK(如 Jedis 连接池泄露)、还是业务代码里反复 EVAL 却不 SCRIPT FLUSH。每次看到 total.allocated 异动,先跑一遍 MEMORY DOCTOR,它比人快。










