redis报oom错误的根本原因包括:内存碎片率过高(mem_fragmentation_ratio>1.5)、maxmemory-policy为noeviction或无效、集群中单节点超限、maxmemory配置过低、客户端/复制等缓冲区隐式占满内存。

如果您在使用 Redis 时收到 OOM command not allowed when used memory > 'maxmemory' 错误,该提示**并不必然表示物理内存真正耗尽**,而是 Redis 检测到当前内存使用状态已触发写入拒绝机制。以下是识别真实原因的步骤:
一、确认是否为“假满”:内存碎片导致的伪 OOM
Redis 的 used_memory(自身统计的净数据+缓冲区)可能远低于 maxmemory,但操作系统实际分配的物理内存 used_memory_rss 因内存碎片严重膨胀,导致 jemalloc 无法拼出连续内存块满足新写入请求——此时即为典型的“假满”。
1、连接 Redis 执行命令:redis-cli INFO memory
2、检查输出中三行关键指标:used_memory、used_memory_rss、mem_fragmentation_ratio
3、计算比值:mem_fragmentation_ratio = used_memory_rss / used_memory;若该值 > 1.5 且 used_memory ,则 90% 为内存碎片所致。
二、确认是否为淘汰策略禁用导致的真阻塞
当 used_memory ≥ maxmemory 且配置的 maxmemory-policy 为 noeviction(默认值)时,Redis 不驱逐任何键,直接拒绝所有写命令——这是设计上的主动保护,而非内存不足的被动崩溃。
1、执行命令:redis-cli CONFIG GET maxmemory-policy
2、若返回值为 noeviction,或返回 volatile-lru 等但实例中**无任何带 TTL 的键**,则写入必然被拒。
3、注意:即使 used_memory_human 显示“还剩 200MB”,只要策略为 noeviction,这 200MB 也不会被用于新写入。
三、确认是否为节点级局部内存超限(集群环境)
在 Redis Cluster 中,每个分片(shard)独立维护 maxmemory 和内存使用统计。报错可能仅发生在某一个哈希槽所在节点,而非全集群整体满载——此时其他节点仍可正常写入,但客户端路由到该节点的请求将失败。
1、获取集群各节点 IP 和端口列表
2、逐个连接节点并执行:redis-cli -h [ip] -p [port] -a [auth] INFO memory | grep -E "(used_memory_human|maxmemory_human)"
3、比对各节点的 used_memory_human / maxmemory_human 比值,定位具体超限节点
四、确认是否为内存限制配置过低(非容量问题)
某些部署环境(如 Oneinstack、phpEnv 或容器化部署)默认设置的 maxmemory 值极小(例如 473MB),远低于业务实际需求。此时 used_memory 很快触顶,但系统仍有大量空闲物理内存未被 Redis 使用。
1、执行:redis-cli CONFIG GET maxmemory 查看当前限制(单位为字节)
2、换算为易读单位:例如 473000000 ≈ 451MB
3、对比服务器总内存与业务峰值数据量,判断该限制是否明显偏低
五、确认是否为元数据或缓冲区隐式占用(非键值数据)
Redis 内存不仅用于存储 key-value,还包括客户端输出缓冲区(output buffer)、复制积压缓冲区(repl-backlog)、AOF 缓冲区、Lua 脚本内存等。这些区域若因网络延迟、从库断连、大 key 扫描等原因持续积压,会推高 used_memory,但不体现为用户可见的键数量增长。
1、执行:redis-cli CLIENT LIST 查看各客户端的 omem(输出缓冲区内存)字段
2、执行:redis-cli INFO replication 检查 repl_backlog_active 和 repl_backlog_size
3、执行:redis-cli INFO clients 观察 client_longest_output_list 是否异常增长











