Redis 内存溢出 OOM 导致消息队列丢失数据怎么办?

文章导读
遇到 Redis 因内存溢出(OOM)导致消息队列数据丢失,首要任务是恢复服务并防止进程被系统杀死,随后再调整内存策略或扩容。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 参考来源
A A

遇到 Redis 因内存溢出(OOM)导致消息队列数据丢失,首要任务是恢复服务并防止进程被系统杀死,随后再调整内存策略或扩容。

先说结论:Redis 内存溢出通常是因为触及 maxmemory 限制或被操作系统 OOM Killer 终止,需先紧急释放内存或重启服务,再根据业务场景调整淘汰策略。

  • 先确认:检查 Redis 内存使用率及系统日志,区分是 Redis 内部限制还是操作系统强制杀死进程。
  • 先处理:临时调大 maxmemory 或清理无用 Key,确保服务可用,避免直接重启导致持久化数据丢失。
  • 再验证:观察内存增长趋势,确认消息队列消费速度是否跟上生产速度,防止再次积压。

命令速用版

# 查看内存使用情况
INFO memory

# 查看最大内存限制
CONFIG GET maxmemory

# 查看当前淘汰策略
CONFIG GET maxmemory-policy

# 自动化查找大 Key(推荐)
redis-cli `--bigkeys`

# 查看指定 Key 内存占用(需指定 key)
MEMORY USAGE keyname

# 手动释放内存(异步删除无用 Key)
UNLINK keyname

为什么会这样

Redis 消息队列数据丢失通常由两种情况引起。第一种是 Redis 配置了 maxmemory 且淘汰策略(maxmemory-policy)设置不当。例如策略为 noeviction 时,写入会报错;若为 allkeys-lru,可能会误删消息队列的 Key。第二种是操作系统层面的 OOM Killer。当 Redis 占用物理内存过高,Linux 内核可能直接杀死 Redis 进程,导致未持久化的数据丢失。

消息队列场景下,数据通常存储在 List 或 Stream 结构中。如果 Redis 进程重启且未开启持久化,或持久化文件损坏,内存中的数据就会消失。此外,如果生产者速度远大于消费者,内存积压会迅速触发限制。

Redis 内存溢出 OOM 导致消息队列丢失数据怎么办?

分步处理

1. 确认故障类型
登录服务器,查看系统日志确认是否触发 OOM Killer。执行命令:

dmesg | grep -i "out of memory"
如果看到 Killed process 字样,说明是操作系统杀死了 Redis。如果没有,检查 Redis 日志看是否有 maxmemory 相关报错。

2. 紧急恢复服务
如果是进程被杀,尝试重启 Redis。注意:务必使用原配置文件启动,确保持久化路径(dir/dbfilename)指向原有数据文件,避免数据永久丢失。若配置文件损坏,需从备份恢复配置。
如果是内存满导致写入失败,可临时调大内存限制(需确保物理内存足够):

CONFIG SET maxmemory 2gb
警告:生产环境严禁随意设置 maxmemory 为 0(不限制),否则极易耗尽物理内存再次触发系统 OOM Killer。设置值应小于物理内存的 70%-80%。

3. 清理积压数据
检查消息队列 Key 的大小。使用 redis-cli `--bigkeys` 定位大 Key。如果是 List 结构,确认消费者是否正常消费。对于无效数据,使用 UNLINK 命令异步删除,避免阻塞主线程:

UNLINK large_key_name
若 Key 极大,建议编写脚本分批删除,避免单次操作耗时过长。

4. 调整淘汰策略与持久化
根据业务重要性修改 maxmemory-policy。对于消息队列,通常不建议使用 volatile-lru,因为消息 Key 可能没有设置过期时间。若允许丢失旧消息,可选 allkeys-lru;若不允许丢失,应确保内存充足并设置 noeviction 配合监控报警。
Stream 结构特别建议:使用 Stream 作为队列时,建议开启 AOF 持久化(appendfsync everysec),并配合 XTRIM 命令限制最大长度,防止无限增长。

Redis 内存溢出 OOM 导致消息队列丢失数据怎么办?

怎么验证是否生效

执行 INFO memory 命令,观察 used_memory_human 数值是否稳定或下降。查看 Redis 日志,确认没有新的 OOM 报错或连接被重置记录。对于消息队列,监控队列长度指标,确认消费速率是否回升。如果是操作系统 OOM 问题,持续观察 dmesg 日志,确保不再出现杀死进程的记录。

监控报警配置示例:
建议配置监控项,当 used_memory_ratio > 0.8 或 evicted_keys 增长过快时触发报警。例如 Prometheus 规则:

redis_memory_used_bytes / redis_memory_max_bytes > 0.8

常见坑

1. 误用淘汰策略:消息队列 Key 若未设置 TTL,使用 volatile 开头的策略不会生效,导致内存满后写入失败。
2. 持久化阻塞:开启 AOF 或 RDB 时,若内存过大,持久化过程可能占用大量内存或 CPU,加剧 OOM 风险。
3. 大 Key 删除阻塞:直接 DEL 大 Key 会阻塞主线程,导致消息处理延迟,建议使用 UNLINK 或分批删除。
4. 忽略碎片率:INFO memory 中的 mem_fragmentation_ratio 过高也会占用额外内存,可通过重启或 CONFIG SET activedefrag yes 优化。
5. maxmemory 设置过大:设置为 0 或接近物理内存上限,会导致操作系统 OOM Killer 介入,建议预留 20% 以上物理内存给系统。

参考来源

  • Redis 官方文档 - 内存管理 (Memory Management)
  • Redis 官方文档 - 淘汰策略 (Eviction policies)