Redis 报内存溢出时,先不要急着改 maxmemory 或扩内存。多数情况是某一层先出了问题:数据写入速度超过淘汰速度、过期策略没生效、单个大 key 长期不释放,或者只是客户端看到的报错被误判成内存不够。排查顺序通常是先定位问题在哪一层,再看日志、命令输出、配置项和面板字段,然后按成因可能性从高到低排除,最后用命令确认修改有效并准备回滚。
Redis 内存溢出通常需要按“定位层 → 看四个位置 → 按概率排除 → 验证回滚”的顺序处理。判断依据是INFO memory里的used_memory、maxmemory、evicted_keys,以及慢查询和客户端写入量。不建议第一时间放宽maxmemory,应先确认是可淘汰数据增长还是不可淘汰数据堆积;内存上限、淘汰策略和过期时间的取值需要结合业务写入量与实例规格确认。
Redis内存溢出先定位在哪一层
Redis 的“内存溢出”至少有四种表现:OOM command not allowed when used memory > 'maxmemory'、写入失败但读正常、实例被系统 OOM Killer 杀掉、客户端连接超时。它们对应的层不一样,改错地方容易反复。
下面按层给出检查位置和判断依据:
- Redis 进程层:执行
redis-cli -h 主机 -p 端口 INFO memory,看used_memory与maxmemory的关系。如果used_memory接近maxmemory且evicted_keys不增长,说明淘汰没有生效。 - 键空间层:执行
redis-cli -h 主机 -p 端口 DBSIZE,再配合SCAN抽样看大 key。如果键数量稳定但内存持续涨,重点查大 key 和未设置 TTL 的键。 - 客户端层:检查应用侧是否在循环写入、批量写入没有分批、或者缓存 key 没有设置过期时间。可以用
redis-cli MONITOR短时间观察写入模式,但不要在高负载实例上长时间开着。 - 系统层:在宿主机执行
free -m和dmesg -T | grep -i oom,确认 Redis 是否被系统 OOM Killer 终止过。如果 Redis 进程被杀,INFO memory往往看不到溢出记录,需要从系统日志反推。
判断原则是:Redis 自己报 OOM 命令错误,优先看 maxmemory 和淘汰策略;Redis 进程消失或被重启,优先看系统内存和 OOM Killer;写入慢但不断报错,优先看客户端写入模式和大 key。
Redis内存溢出:先看这四个位置
定位到大致层之后,按下面四个位置拿证据。命令里的主机、端口、密码占位需要换成实际环境值,密码建议用 REDISCLI_AUTH 环境变量传入,避免出现在命令历史里。
1. Redis 日志
先在配置文件里确认 logfile 路径,或者用 redis-cli CONFIG GET logfile 查当前路径。常见位置是 /var/log/redis/redis-server.log 或 /var/log/redis/redis.log,需要以实际配置为准。查看命令:
tail -n 200 /var/log/redis/redis-server.log
# 关注包含 OOM、maxmemory、evict、fork、Background 的行
grep -iE 'oom|maxmemory|evict|out of memory' /var/log/redis/redis-server.log
日志里如果出现 OOM command not allowed,说明 Redis 自身已经达到上限;如果出现 Background save fork failed,则可能是持久化 fork 时内存翻倍导致的问题,和单纯的键值增长不是一回事。

2. 命令输出
用 INFO memory 一次拿到关键字段,不要只看一个总数:
redis-cli -h 127.0.0.1 -p 6379 INFO memory | grep -E 'used_memory_human|used_memory_peak_human|maxmemory_human|maxmemory_policy|mem_fragmentation_ratio|evicted_keys'
再查淘汰和过期情况:
redis-cli -h 127.0.0.1 -p 6379 INFO stats | grep -E 'evicted_keys|expired_keys|keyspace_hits|keyspace_misses'
mem_fragmentation_ratio 明显大于 1 时,内存碎片占了一部分;used_memory_peak_human 远高于当前值,说明曾经有过峰值,需要结合业务高峰判断。
3. 配置项
把实际生效的配置查出来,而不是只看配置文件:
redis-cli -h 127.0.0.1 -p 6379 CONFIG GET maxmemory
redis-cli -h 127.0.0.1 -p 6379 CONFIG GET maxmemory-policy
redis-cli -h 127.0.0.1 -p 6379 CONFIG GET maxmemory-samples
maxmemory 为 0 表示不限制,此时如果报 OOM,问题通常来自系统内存或客户端,不是 Redis 自身上限;maxmemory-policy 为 noeviction 时,达到上限后写入会直接失败,这是排查中最常见的配置原因之一。
4. 监控面板字段
如果使用云厂商 Redis 或自建 Prometheus 监控,先确认面板上这几个字段的实际含义:内存使用量、内存使用率、被淘汰 key 数、过期 key 数、连接数、每秒写入量。不同面板对“内存使用率”的算法可能不同,有的按 used_memory 算,有的按系统 RSS 算,需要看面板说明或指标定义。比较稳妥的做法是用 INFO memory 的输出与面板对照一次,确认两者是否一致。

Redis内存溢出:按可能性从高到低排除
下面按实际排查中出现频率从高到低排列。每个成因后面给出确认动作和处理方向,确认不了就先不要改配置。
- 淘汰策略为 noeviction 或没有设置过期时间。确认动作:
redis-cli CONFIG GET maxmemory-policy,以及用SCAN 0 COUNT 1000抽样配合TTL key看键是否有过期时间。处理方向:根据业务能否丢数据选择allkeys-lru或volatile-lru,并为缓存键补上 TTL。不能淘汰的数据不要和可淘汰缓存放在同一实例。 - 大 key 或热 key 长期占用内存。确认动作:
redis-cli --bigkeys -h 127.0.0.1 -p 6379,或在从节点上执行,避免影响主节点。处理方向:拆分大 hash、大 list,控制单个 value 大小;已经写入的历史大 key 需要评估删除或迁移的影响,不要直接在业务高峰执行DEL大 key,可以用UNLINK异步删除。 - 写入量突增或缓存击穿后全量回填。确认动作:观察
INFO stats里的total_commands_processed增长速率,或用MONITOR短时间采样写入命令类型。处理方向:在应用侧加分批写入、限制并发回填,必要时在缓存层加短 TTL 防止同一批 key 同时过期。 - 持久化 fork 导致内存峰值翻倍。确认动作:查看日志中
Background saving started与失败记录,对比used_memory_peak_human和当前值。处理方向:控制实例内存不超过系统可用内存的一半左右,或将持久化放到从节点,具体比例需要结合写入放大和系统内存确认。 - 内存碎片或客户端缓冲区占用。确认动作:看
INFO memory中的mem_fragmentation_ratio和INFO clients中的client_recent_max_input_buffer、client_recent_max_output_buffer。处理方向:碎片持续偏高时可评估activedefrag,客户端缓冲区异常时检查是否有慢客户端或大范围KEYS、SMEMBERS类命令。
处理时优先动配置和写入侧,不要一上来就扩内存。扩内存能暂时缓解,但如果成因是大 key 或不设过期时间,扩容后仍会再次溢出。
Redis内存溢出:改完怎么确认真的解决了
修改之后需要从命令输出和监控两个方向确认。下面这组命令可以每隔一段时间执行一次,对比数值变化:
redis-cli -h 127.0.0.1 -p 6379 INFO memory | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'
redis-cli -h 127.0.0.1 -p 6379 INFO stats | grep -E 'evicted_keys|expired_keys'
redis-cli -h 127.0.0.1 -p 6379 DBSIZE
判断稳定的依据通常是:used_memory 在业务高峰后能回落或保持平稳,evicted_keys 不再持续快速增长,应用侧不再出现 OOM 写入报错。观察时长建议至少覆盖一个完整业务高峰周期,比如一个工作日加上夜间低谷;如果业务有明显周期性,最好跨过一个高峰再判断。没有覆盖高峰就宣布解决,容易在下一个高峰复现。
回滚办法要提前准备好。以调整 maxmemory-policy 为例,修改前先记录原值:
# 修改前记录
redis-cli CONFIG GET maxmemory-policy > /tmp/redis-maxmemory-policy.bak
# 修改
redis-cli CONFIG SET maxmemory-policy allkeys-lru
# 回滚
redis-cli CONFIG SET maxmemory-policy "$(awk 'NR==2{print}' /tmp/redis-maxmemory-policy.bak)"
如果用 CONFIG SET 改的是运行中配置,重启后会回到配置文件里的值,需要同步修改配置文件并确认加载路径。回滚时同样用 CONFIG SET 改回原值,并用 CONFIG GET 确认生效。涉及删除大 key 的操作无法直接回滚,执行前应先确认 key 能否从源数据重建,或者先导出再删除。