线上 Redis 内存溢出 OOM 导致消息队列不可用怎么紧急恢复?

文章导读
紧急情况下,优先通过动态调整 Redis 配置释放写入权限,同时评估是否可接受临时数据淘汰,避免直接重启导致服务中断。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 参考来源
A A

紧急情况下,优先通过动态调整 Redis 配置释放写入权限,同时评估是否可接受临时数据淘汰,避免直接重启导致服务中断。

先说结论:Redis 报 OOM 错误通常是因为达到 maxmemory 上限且策略为 noeviction,需先恢复写入能力再排查根因。

  • 先确认:登录 Redis 检查内存使用率及当前淘汰策略,确认是否为配置限制而非进程崩溃
  • 先处理:动态调大内存上限或临时改为淘汰策略(警告:队列场景慎用 LRU),必要时使用工具扫描大 Key
  • 再验证:观察消息队列积压是否减少,监控内存增长趋势,务必持久化配置

命令速用版

# 查看内存使用情况
INFO memory

# 查看当前内存上限及策略
CONFIG GET maxmemory
CONFIG GET maxmemory-policy

# 紧急扩容(单位字节,例如 2GB)
CONFIG SET maxmemory 2147483648

# 临时改为自愿淘汰策略(高风险:可能丢数据)
CONFIG SET maxmemory-policy allkeys-lru

# 自动扫描大 Key(客户端执行,非 Redis 命令)
redis-cli -h 127.0.0.1 -p 6379 `--bigkeys`

# 配置持久化(防止重启失效)
CONFIG REWRITE

# 查看占用内存最大的 Key(需已知 key 名)
MEMORY USAGE keyname

为什么会这样

Redis 内存溢出通常指两种情况:一种是 Redis 进程自身达到配置的上限(maxmemory),另一种是操作系统因内存不足杀死进程(OOM Killer)。消息队列不可用大多是因为前者,当 Redis 内存使用量达到上限且淘汰策略设置为 noeviction(默认)时,所有写入命令会返回 OOM 错误,导致依赖 Redis 存储 offset 或状态的消息队列组件无法写入。

如果未设置 maxmemory,Redis 会持续占用物理内存,直到触发操作系统的 OOM Killer 机制被强制杀死,此时连接会直接断开。具体触发阈值取决于服务器剩余可用内存和内核参数,无固定数值。

分步处理

1. 确认故障现象
通过 Redis 客户端执行命令,如果返回 (error) OOM command not allowed when used memory > 'maxmemory',说明是配置限制。如果连接直接拒绝,可能是进程已崩溃。

2. 动态调整内存上限
如果服务器物理内存仍有剩余,可在线调大上限。执行 CONFIG SET maxmemory <bytes>。注意不要超过物理内存的 80%,预留空间给操作系统和其他进程。

3. 调整淘汰策略(高风险)
如果无法增加物理内存,可临时修改策略为 allkeys-lru 或 volatile-lru。执行 CONFIG SET maxmemory-policy allkeys-lru。严重警告:若 Redis 用于存储消息队列数据(如 List/Stream),LRU 策略可能导致未消费的消息被当作旧数据淘汰,造成数据丢失。仅建议在确认业务可容忍丢失或仅存储缓存数据时使用。

线上 Redis 内存溢出 OOM 导致消息队列不可用怎么紧急恢复?

4. 自动扫描大 Key
紧急情况下无法预知 Key 名,不建议直接使用 MEMORY USAGE。请使用 redis-cli 工具扫描:
redis-cli -h <host> -p <port> `--bigkeys`
该命令会遍历数据库找出占用内存最大的 Key。如果是业务缓存,可手动 DEL 删除。避免使用 KEYS 命令,防止阻塞单线程。

5. 配置持久化
CONFIG SET 命令仅修改运行时配置,重启后失效。紧急恢复后务必执行 CONFIG REWRITE 将当前配置写入 redis.conf 文件,或手动修改配置文件,防止重启后故障复发。

6. 重启服务(最后手段)
如果配置无法动态生效或进程已挂,需重启 Redis。重启前确认 RDB 或 AOF 持久化文件完整,避免数据丢失。重启后立即检查配置文件中的 maxmemory 设置。

怎么验证是否生效

1. 写入测试
在 Redis 客户端执行 SET test_key 1,确认不再返回 OOM 错误。

2. 业务监控
观察消息队列的控制台或日志,确认生产者和消费者状态由 Error 转为 Normal。

线上 Redis 内存溢出 OOM 导致消息队列不可用怎么紧急恢复?

3. 积压检查
针对 Redis 实现的队列,检查队列长度变化。例如 List 结构执行 LLEN queue_name,Stream 结构执行 XINFO STREAM stream_name,确认积压消息开始减少。

4. 内存监控
持续执行 INFO memory,观察 used_memory_human 是否稳定在 new maxmemory 以下,且不再快速上涨。

常见坑

1. 配置未持久化
CONFIG SET 命令仅修改运行时配置,重启后失效。紧急恢复后务必修改 redis.conf 文件并重启或执行 CONFIG REWRITE。

2. 策略误改导致数据丢失
将 noeviction 改为 allkeys-lru 可能导致热点数据被淘汰。特别是消息队列场景,未消费消息可能因时间较早被优先淘汰,业务恢复后应评估是否需要改回原策略或优化数据结构。

3. 忽略从节点压力
主节点恢复后,复制流量可能瞬间打满从节点内存。检查集群中所有节点的内存状态,避免雪崩。必要时临时断开复制链路。

4. 大 Key 删除阻塞
直接 DEL 大 Key 会阻塞 Redis 主线程。建议使用 UNLINK 命令异步删除,或分批处理。

参考来源

  • Redis Official Documentation, Memory Management, https://redis.io/docs/latest/develop/management/memory-management/
  • Redis Official Documentation, CONFIG SET, https://redis.io/docs/latest/develop/reference/cli/