如何通过开启监控和堆栈工具定位查大Key引发的OOM问题?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1122个文字,预计阅读时间需要5分钟。
使用 `redis-cli --bigkeys` 命令可以统计每个 key 的序列化后字节数,不包括 Redis 内部数据结构(如 dictEntry、sds、指针等)。实际内存占用通常比显示的高 30% 到 100%。对于 `hash` 或 `zset` 类型,元素越多,额外开销越明显。
它也不区分 key 是否带过期时间(EXPIRE)、是否被频繁访问(影响 LRU/LFU 淘汰权重),更不会告诉你该 key 是否正在被客户端缓冲区大量读取(比如 CLIENT LIST 中 obuf 高的连接可能正卡在读一个大 list)。
- 线上紧急排查时,优先用它快速筛出 top N 大 key,但别把它当唯一依据
- 若扫描结果里没发现明显大 key,但
used_memory持续飙升,重点看mem_fragmentation_ratio和client_longest_output_list - 它不阻塞服务,但会遍历全库 —— 在高 QPS 实例上慎用,建议在低峰期执行
离线分析 RDB 文件时,-bytes 参数设多少才合理?
设 -bytes 1024 是常见起点,但实际要结合业务 value 分布来调。比如你业务中正常 string key 值基本在 500B 左右,那设 1024 就能覆盖异常;但如果普遍存 JSON,平均 8KB,再设 1024 就会刷出太多噪音。
更稳妥的做法是先用 INFO memory 查 used_memory 和 dbX 下 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 LIST找obuf> 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 报错,二者必须交叉验证。
如果 dmesg 有 Killed process redis-server (pid 12345),但 Redis 日志里没 OOM 报错,说明是系统层内存不足(比如其他进程吃光内存),Redis 只是被顺手 kill 的倒霉蛋。
- 执行
dmesg -T | grep -i "killed process" | tail -20,注意时间戳是否贴近 Redis 宕机时刻 -
free -h和cat /proc/meminfo中的MemAvailable比MemFree更真实反映可用内存 - Redis 自身日志里的
used_memory_peak如果远高于maxmemory,说明之前就发生过内存尖峰,只是没立刻崩溃
OBJECT FREQ 和 CLIENT LIST 的组合输出,比单纯看大小有用得多。本文共计1122个文字,预计阅读时间需要5分钟。
使用 `redis-cli --bigkeys` 命令可以统计每个 key 的序列化后字节数,不包括 Redis 内部数据结构(如 dictEntry、sds、指针等)。实际内存占用通常比显示的高 30% 到 100%。对于 `hash` 或 `zset` 类型,元素越多,额外开销越明显。
它也不区分 key 是否带过期时间(EXPIRE)、是否被频繁访问(影响 LRU/LFU 淘汰权重),更不会告诉你该 key 是否正在被客户端缓冲区大量读取(比如 CLIENT LIST 中 obuf 高的连接可能正卡在读一个大 list)。
- 线上紧急排查时,优先用它快速筛出 top N 大 key,但别把它当唯一依据
- 若扫描结果里没发现明显大 key,但
used_memory持续飙升,重点看mem_fragmentation_ratio和client_longest_output_list - 它不阻塞服务,但会遍历全库 —— 在高 QPS 实例上慎用,建议在低峰期执行
离线分析 RDB 文件时,-bytes 参数设多少才合理?
设 -bytes 1024 是常见起点,但实际要结合业务 value 分布来调。比如你业务中正常 string key 值基本在 500B 左右,那设 1024 就能覆盖异常;但如果普遍存 JSON,平均 8KB,再设 1024 就会刷出太多噪音。
更稳妥的做法是先用 INFO memory 查 used_memory 和 dbX 下 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 LIST找obuf> 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 报错,二者必须交叉验证。
如果 dmesg 有 Killed process redis-server (pid 12345),但 Redis 日志里没 OOM 报错,说明是系统层内存不足(比如其他进程吃光内存),Redis 只是被顺手 kill 的倒霉蛋。
- 执行
dmesg -T | grep -i "killed process" | tail -20,注意时间戳是否贴近 Redis 宕机时刻 -
free -h和cat /proc/meminfo中的MemAvailable比MemFree更真实反映可用内存 - Redis 自身日志里的
used_memory_peak如果远高于maxmemory,说明之前就发生过内存尖峰,只是没立刻崩溃
OBJECT FREQ 和 CLIENT LIST 的组合输出,比单纯看大小有用得多。
