Redis内存暴涨,没想到是AOF重写捣的鬼

文章来源声明: 原文作者:阿橙的百宝箱; 来源站点:掘金; 原文链接:https://juejin.cn/post/7705228164604592143; 本文基于上述来源整理/加工,觅优补充点评,仅供技术学习交流。版权归原作者所有。
觅优短评

案例把AOF重写的COW内存放大讲透了,适合运维与后端排查Redis间歇性OOM时参考;从大key治理和重写调度入手,能快速止损并降低复发风险。

### 凌晨三点的告警:Redis突然吃掉了16GB内存

那天夜里,线上核心业务的Redis实例内存突然从8GB飙升至24GB,触发OOM告警。这个集群平时QPS稳定在3万左右,AOF和RDB都开着,数据量约6GB。重启后内存缓慢增长,但一周后再次爆炸——你有没有遇到过这种“间歇性内存抽风”的情况?

AOF重写的隐藏成本

表面看是内存泄漏,但INFO命令显示aof_rewrite_in_progress:1时内存激增。问题的本质在于Redis的AOF重写机制:

  1. 子进程的写时复制(COW)陷阱:AOF重写由bgrewriteaof触发的子进程完成,理论上不会阻塞主进程。但子进程需要遍历当前DB快照,此时主进程继续处理写请求——你以为COW能完美共享内存?太天真了。
  2. 大key的死亡拥抱:当主进程修改某个存在的大key(比如10MB的Hash),Linux的COW机制会触发整个key的内存复制。我们的业务恰好在AOF重写期间批量更新了一批商户画像的Hash结构。
# 用以下命令抓出内存暴涨时的罪魁祸首
redis-cli --bigkeys
# 输出示例:
# Biggest string found 'user:ranking' has 12 bytes
# Biggest hash   found 'merchant:profile:1089' has 12098342 bytes

从内核视角看内存翻倍

用smem工具抓取Redis进程的PSS(实际物理内存占用),发现:

阶段内存(GB)备注
正常运行时8.2RDB内存快照约7.5GB
AOF重写开始后10分钟15.7主进程修改了20个大Hash
AOF重写完成时9.1子进程退出后释放复制内存
  • 关键结论*:COW机制下,子进程持有旧数据页,主进程修改数据会触发新内存分配。如果重写期间频繁改动大key,内存可能短暂膨胀到原数据的2倍!

代码层的两记闷棍

你以为开了AOF就高枕无忧?看看这段错误配置:

# redis.conf 踩坑配置
auto-aof-rewrite-percentage 100  # 默认触发阈值
auto-aof-rewrite-min-size 64mb   # 太小!大集群易频繁触发
appendfsync everysec             # 生产环境谨慎用always!

  • 更糟的是*:某些客户端库在AOF重写期间仍疯狂写入:
// 错误写法:无视Redis状态循环写入大对象
public void updateMerchantProfile(long merchantId, Map<String, String> profile) {
    jedis.hset("merchant:profile:" + merchantId, profile); // 单个value 10MB+
}

  • 正确做法*:至少要做三件事——
// 1. 监控AOF重写状态
if (jedis.info("persistence").contains("aof_rewrite_in_progress:1")) {
    delayUpdate(queue, profile); // 进入队列延迟处理
}
// 2. 拆分大Hash
public void updateMerchantProfile(long merchantId, String field, String value) {
    jedis.hset("merchant:profile:" + merchantId, field, value); // 字段级更新
}
// 3. 限流
RateLimiter rateLimiter = RateLimiter.create(5000); // QPS控制

避坑指南:AOF重写的五个生死劫

  1. 大key炸弹:重写前用redis-cli --bigkeys扫描,拆分超过1MB的key
  2. 频繁触发:调整auto-aof-rewrite-min-size到当前内存的5%-10%
  3. 写风暴:重写期间通过CLIENT PAUSE暂停非关键写入(Redis 6.2+支持暂停类型)
  4. 磁盘IO雪崩:避免appendfsync always与AOF重写同时发生
  5. 版本差异:Redis 7.0的Multi Part AOF能缓解此问题,但COW机制依然存在

终极解法:让子弹飞一会儿

现在的方案很暴力但有效:

  • 在低峰期通过BGREWRITEAOF手动触发重写

  • 重写期间降级非核心功能

  • 彻底重构大key为分片结构

  • 血泪总结*:AOF重写不是免费的午餐。当你的Redis内存莫名翻倍时,先看看是不是这个“老实人”在搞事。

你在业务中如何处理AOF重写问题?欢迎聊聊你的实战解法。