现场是这样的。持久化开始报错,日志里写无法分配内存,实例本身内存还有余量,但每次保存都失败。
真正麻烦的地方在于,几个原因的现象几乎一样。系统剩余内存不足,fork 时的写时复制需要额外空间;开启了透明大页,复制页表的开销被放大;实例内存超过物理内存一半,余量不够。
上来先看内存与复制相关统计
redis-cli info memory | grep -E 'used_memory_rss|mem_fragmentation_ratio'
接着确认系统剩余内存
free -h && grep MemAvailable /proc/meminfo
再往下关闭透明大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
限制实例最大内存并留余量
redis-cli config set maxmemory 2gb
白天有业务在跑,能验证的部分都压到了晚上做。
当时还开着另一个排查窗口,两边日志对照着看才定位到。
别只看报错消失,验证要多做一步。持久化不再报内存分配失败,保存能在秒级完成,数据文件正常更新。
容易忽略的是,写时复制期间父进程和子进程共享内存,最坏情况要翻倍;实例内存别贴着物理内存上限配置。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。