如何通过开启监控和堆栈工具定位查大Key引发的OOM问题?

2026-05-07 02:242阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1122个文字,预计阅读时间需要5分钟。

如何通过开启监控和堆栈工具定位查大Key引发的OOM问题?

使用 `redis-cli --bigkeys` 命令可以统计每个 key 的序列化后字节数,不包括 Redis 内部数据结构(如 dictEntry、sds、指针等)。实际内存占用通常比显示的高 30% 到 100%。对于 `hash` 或 `zset` 类型,元素越多,额外开销越明显。

它也不区分 key 是否带过期时间(EXPIRE)、是否被频繁访问(影响 LRU/LFU 淘汰权重),更不会告诉你该 key 是否正在被客户端缓冲区大量读取(比如 CLIENT LISTobuf 高的连接可能正卡在读一个大 list)。

  • 线上紧急排查时,优先用它快速筛出 top N 大 key,但别把它当唯一依据
  • 若扫描结果里没发现明显大 key,但 used_memory 持续飙升,重点看 mem_fragmentation_ratioclient_longest_output_list
  • 它不阻塞服务,但会遍历全库 —— 在高 QPS 实例上慎用,建议在低峰期执行

离线分析 RDB 文件时,-bytes 参数设多少才合理?

-bytes 1024 是常见起点,但实际要结合业务 value 分布来调。比如你业务中正常 string key 值基本在 500B 左右,那设 1024 就能覆盖异常;但如果普遍存 JSON,平均 8KB,再设 1024 就会刷出太多噪音。

更稳妥的做法是先用 INFO memoryused_memorydbX 下 key 数量,粗算平均 key 占用:比如 2GB / 200 万 key ≈ 1KB/个,那么 -bytes 5000 更有诊断价值。

  • rdb_bigkeys 输出的 serializedlength 是压缩后长度,和 redis-cli --bigkeys 的值接近,但更准(因为基于磁盘文件,不含运行时缓存扰动)
  • 务必加 -sorted,否则输出无序,难定位 top 几个真凶
  • 线程数 -threads 4 在 8 核机器上够用;超过 8 线程收益递减,还可能抢 I/O

查到大 key 后,怎么确认它就是 OOM 根因?

不能只看单个 key 大小。关键要看它是否「高频+高内存+不可淘汰」:

  • OBJECT FREQ keyname 查 LRU 频率(仅限 allkeys-lru 等策略下有效),值接近 255 表示刚被访问过
  • TTL keyname 看是否永不过期 —— 永久 key + 大体积 = 长期占内存
  • CLIENT LISTobuf > 1MB 的连接,再用 CLIENT GETNAME 关联业务标识,确认是不是某个下游服务在轮询拉取这个大 list
  • 检查 maxmemory-policy:如果是 noeviction,写入大 key 直接触发 OOM command not allowed;如果是 allkeys-lru,但大 key 访问冷,也容易被误删导致业务异常

堆栈工具抓不到 Redis 进程?dmesg 和日志得一起看

Redis 是单线程 C 程序,没有 JVM 那种堆快照概念,所谓「堆栈」在这里指系统级现场:dmesg 看 OOM Killer 是否干掉了它,/var/log/redis/redis-server.log 看是否有 OOM command not allowed 报错,二者必须交叉验证。

如果 dmesgKilled process redis-server (pid 12345),但 Redis 日志里没 OOM 报错,说明是系统层内存不足(比如其他进程吃光内存),Redis 只是被顺手 kill 的倒霉蛋。

  • 执行 dmesg -T | grep -i "killed process" | tail -20,注意时间戳是否贴近 Redis 宕机时刻
  • free -hcat /proc/meminfo 中的 MemAvailableMemFree 更真实反映可用内存
  • Redis 自身日志里的 used_memory_peak 如果远高于 maxmemory,说明之前就发生过内存尖峰,只是没立刻崩溃
真正卡住人的地方,往往不是找不到大 key,而是搞不清它为什么“活”着 —— 没过期、没被淘汰、还在被某个长连接反复读。定位时盯着 OBJECT FREQCLIENT LIST 的组合输出,比单纯看大小有用得多。
标签:工具

本文共计1122个文字,预计阅读时间需要5分钟。

如何通过开启监控和堆栈工具定位查大Key引发的OOM问题?

使用 `redis-cli --bigkeys` 命令可以统计每个 key 的序列化后字节数,不包括 Redis 内部数据结构(如 dictEntry、sds、指针等)。实际内存占用通常比显示的高 30% 到 100%。对于 `hash` 或 `zset` 类型,元素越多,额外开销越明显。

它也不区分 key 是否带过期时间(EXPIRE)、是否被频繁访问(影响 LRU/LFU 淘汰权重),更不会告诉你该 key 是否正在被客户端缓冲区大量读取(比如 CLIENT LISTobuf 高的连接可能正卡在读一个大 list)。

  • 线上紧急排查时,优先用它快速筛出 top N 大 key,但别把它当唯一依据
  • 若扫描结果里没发现明显大 key,但 used_memory 持续飙升,重点看 mem_fragmentation_ratioclient_longest_output_list
  • 它不阻塞服务,但会遍历全库 —— 在高 QPS 实例上慎用,建议在低峰期执行

离线分析 RDB 文件时,-bytes 参数设多少才合理?

-bytes 1024 是常见起点,但实际要结合业务 value 分布来调。比如你业务中正常 string key 值基本在 500B 左右,那设 1024 就能覆盖异常;但如果普遍存 JSON,平均 8KB,再设 1024 就会刷出太多噪音。

更稳妥的做法是先用 INFO memoryused_memorydbX 下 key 数量,粗算平均 key 占用:比如 2GB / 200 万 key ≈ 1KB/个,那么 -bytes 5000 更有诊断价值。

  • rdb_bigkeys 输出的 serializedlength 是压缩后长度,和 redis-cli --bigkeys 的值接近,但更准(因为基于磁盘文件,不含运行时缓存扰动)
  • 务必加 -sorted,否则输出无序,难定位 top 几个真凶
  • 线程数 -threads 4 在 8 核机器上够用;超过 8 线程收益递减,还可能抢 I/O

查到大 key 后,怎么确认它就是 OOM 根因?

不能只看单个 key 大小。关键要看它是否「高频+高内存+不可淘汰」:

  • OBJECT FREQ keyname 查 LRU 频率(仅限 allkeys-lru 等策略下有效),值接近 255 表示刚被访问过
  • TTL keyname 看是否永不过期 —— 永久 key + 大体积 = 长期占内存
  • CLIENT LISTobuf > 1MB 的连接,再用 CLIENT GETNAME 关联业务标识,确认是不是某个下游服务在轮询拉取这个大 list
  • 检查 maxmemory-policy:如果是 noeviction,写入大 key 直接触发 OOM command not allowed;如果是 allkeys-lru,但大 key 访问冷,也容易被误删导致业务异常

堆栈工具抓不到 Redis 进程?dmesg 和日志得一起看

Redis 是单线程 C 程序,没有 JVM 那种堆快照概念,所谓「堆栈」在这里指系统级现场:dmesg 看 OOM Killer 是否干掉了它,/var/log/redis/redis-server.log 看是否有 OOM command not allowed 报错,二者必须交叉验证。

如果 dmesgKilled process redis-server (pid 12345),但 Redis 日志里没 OOM 报错,说明是系统层内存不足(比如其他进程吃光内存),Redis 只是被顺手 kill 的倒霉蛋。

  • 执行 dmesg -T | grep -i "killed process" | tail -20,注意时间戳是否贴近 Redis 宕机时刻
  • free -hcat /proc/meminfo 中的 MemAvailableMemFree 更真实反映可用内存
  • Redis 自身日志里的 used_memory_peak 如果远高于 maxmemory,说明之前就发生过内存尖峰,只是没立刻崩溃
真正卡住人的地方,往往不是找不到大 key,而是搞不清它为什么“活”着 —— 没过期、没被淘汰、还在被某个长连接反复读。定位时盯着 OBJECT FREQCLIENT LIST 的组合输出,比单纯看大小有用得多。
标签:工具