确认Redis真OOM需同时满足:used_memory接近或等于maxmemory;INFO memory中evicted_keys为0且maxmemory_policy未生效;mem_fragmentation_ratio>1.5时used_memory_rss已触顶。

Redis 内存溢出不是配置调大就能解决的,得先确认是不是真的 OOM,再定位谁在吃内存、为什么吃、吃得多不多——否则扩容只是把问题拖到下次流量高峰。
怎么快速确认 Redis 真的 OOM 了?
别猜,直接看三个命令的输出是否同时满足以下条件:
-
redis-cli info memory | grep used_memory返回的used_memory接近或等于maxmemory(比如差值 -
redis-cli config get maxmemory显示已配置非零值(不是0或空) - 客户端正在报错:
OOM command not allowed when used memory > 'maxmemory'
如果 used_memory 远低于 maxmemory 却报 OOM,大概率是 mem_fragmentation_ratio 过高(>1.5),物理内存被碎片卡住,used_memory_rss 已撑满系统内存。
哪个 key 在吃内存?用 --bigkeys 还是 memory usage?
redis-cli --bigkeys 是最快上手的扫描方式,但它只抽样、不精确,且对 ZSET 和 HASH 类型只统计元素个数,不反映实际内存占用。真正要定位“谁占得多”,得组合使用:
- 先跑
redis-cli --bigkeys快速揪出 Top 10 大 key 名称和类型 - 对疑似大 key 手动查内存:
redis-cli memory usage <key_name>(注意:该命令会阻塞主线程,生产慎用,优先选低峰期) - 更安全的替代方案:
redis-cli memory stats查看dataset.bytes和各数据结构的total_allocated分布,判断是hash还是string类型整体膨胀
特别注意:如果 memory usage 返回异常高(比如一个 string 显示几百 MB),但 STRLEN 只有几 KB,那很可能是编码问题或元数据开销异常,需结合 OBJECT ENCODING 和 DEBUG OBJECT 进一步验证。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
为什么淘汰策略没起作用?
即使配置了 allkeys-lru,也常出现“明明该淘汰却还在涨”的情况。核心原因有三个:
- 淘汰是被动触发的:只有写入新 key 时才会检查并逐出旧 key;纯读场景不会主动释放
- 大 key 淘汰成本高:一个 50MB 的
ZSET被 LRU 淘汰时,Redis 需分配新空间做渐进式释放,反而可能短暂推高used_memory_rss - 策略匹配失败:比如配置了
volatile-lru,但业务 key 全都没设EXPIRE,那就退化成noeviction,所有写入直接报 OOM
验证方法:redis-cli info stats | grep evicted_keys,如果该值长期为 0,说明淘汰根本没生效,优先检查 maxmemory-policy 是否匹配 key 的过期设置。
碎片高、RSS 爆了,能在线修复吗?
Redis 4.0+ 支持 memory purge 命令,可尝试手动回收 jemalloc 的脏页,但效果有限——它只清理已释放但未归还给操作系统的内存页,对持续写入导致的碎片无效。
- 执行前先看碎片率:
redis-cli info memory | grep mem_fragmentation_ratio - 若 >1.5,先试
redis-cli memory purge,再立刻查used_memory_rss是否下降 - 若无明显变化,说明碎片来自频繁修改大 key 导致的内部 rehash,此时唯一可靠方式是:滚动重启(先切流量、清空从库、主库重启)、或拆分大 key 后重建
容易被忽略的一点:memory purge 不是万能开关,它依赖 jemalloc 的 malloc_stats_print 行为,某些容器环境或自编译版本可能禁用该功能,执行后无报错也不生效。

















