Redis RDB/AOF重写时fork子进程触发Linux COW机制,主进程修改内存页即复制,导致瞬时内存接近翻倍;需为COW预留余量,maxmemory建议设为总内存的60%~70%,并用INFO memory和--bigkeys验证风险。

看懂 RDB/AOF 重写时的内存翻倍原理
Redis 在做 RDB 快照或 AOF 重写时,主进程会 fork 子进程。Linux 的 Copy-On-Write(COW)机制意味着:子进程刚 fork 出来时并不复制全部内存页,但只要主进程修改了某页数据,该页就会被真实复制一份——此时内存占用可能瞬间接近翻倍。
这不是 bug,是 OS 行为;但如果你 maxmemory 设得太紧、又恰逢写入高峰,used_memory + COW 额外开销就很容易突破物理内存上限,触发系统 OOM Killer 杀掉 Redis 进程。
- 典型现象:
redis-server进程突然消失,dmesg | grep -i "killed process"显示它被 OOM Killer 干掉 - 关键线索:
INFO memory中used_memory_peak接近maxmemory,且mem_fragmentation_ratio正常(排除碎片干扰) - 风险放大器:开启
activerehashing yes(默认开启)+ 大量哈希表扩容 + 高频写入 → 更多内存页被 COW
配置 maxmemory 必须预留 COW 余量
不能把 maxmemory 直接设成机器总内存的 80%,得给 fork 后的瞬时内存峰值留出安全空间。经验公式是:maxmemory ≤ (总内存 × 0.6) ~ (总内存 × 0.7),具体取决于你的写入压力和数据结构复杂度。
- 例如:16GB 物理内存服务器,建议
maxmemory不超过10gb,而非12gb - 若业务写入极密集(如每秒数万次 SET/HSET),保守起见压到
8gb更稳妥 - 动态设置命令:
CONFIG SET maxmemory 8gb(需确认配置文件也同步更新,避免重启失效) - 切忌用
maxmemory 0(无限制)——这是生产环境最常见踩坑点之一
用 INFO memory 和 redis-cli --bigkeys 验证风险点
光设了 maxmemory 不够,得验证当前负载下是否真有“重写即崩”的隐患。重点不是看平均内存,而是看峰值和分布。
- 执行
INFO memory,紧盯三个值:used_memory_peak(历史最高)、used_memory(当前)、mem_fragmentation_ratio(若 >1.5,先跑MEMORY PURGE清碎片) - 运行
redis-cli --bigkeys,确认是否存在单个Hash或List占用几百 MB 的“炸弹 Key”——这类 Key 在 RDB 保存时会强制加载进内存,加剧 COW 压力 - 模拟重写测试:
DEBUG SLEEP 0.1后立刻BGREWRITEAOF,同时用top -p $(pgrep redis)观察 RSS 是否飙升超限
替代方案:关 AOF / 改用 RDB + 关闭 save 持久化
如果业务能接受秒级数据丢失(比如纯缓存场景),最直接的规避方式就是砍掉重写源头。
- 停 AOF:
CONFIG SET appendonly no,再删掉appendonly.aof文件(注意备份) - 禁 RDB 自动快照:
CONFIG SET save "",彻底关闭save规则(保留手动SAVE权限) - 注意副作用:失去持久化能力,宕机即丢所有数据;仅适用于明确设计为无状态缓存的集群节点
- 更平衡的做法:保留 RDB,但调大
save间隔(如save 300 10→save 1800 1),大幅降低重写频率







