rss远高于used_memory是内存碎片严重或oom风险的直接信号,mem_fragmentation_ratio持续>1.5尤其rdb时跳至2.0+,需优先排查大key、淘汰策略及fork期间写入高峰,而非盲目调大maxmemory。

redis-cli INFO memory 显示 rss 远高于 used_memory
这是最直接的信号。used_memory 是 Redis 自己统计的数据集内存,而 used_memory_rss 是操作系统看到的物理内存占用。如果 mem_fragmentation_ratio(即 used_memory_rss / used_memory)持续大于 1.5,尤其在触发 RDB 时突然跳到 2.0+,说明 fork 后子进程复制页表产生了大量额外内存开销,系统可能已逼近 OOM 边界。
此时别急着调大 maxmemory,先确认 used_memory 本身是否合理——有没有未清理的大 key、没启用淘汰策略、或业务误存了不该缓存的二进制数据。
检查 dmesg 是否出现 “Killed process redis-server”
执行 dmesg -T | grep -i "killed process",若输出中明确包含 redis-server 和时间戳,基本可锁定是 OOM Killer 主动终止了 Redis 进程(或其 fork 出的 RDB 子进程)。注意:被杀的不一定是主进程,也可能是子进程,但日志里通常只记进程名,不会写“子进程”。
关键要看紧邻该日志前后的内存状态,例如是否有 Out of memory: Kill process [pid] (redis-server) 或 oom_score_adj 值偏高。后者说明内核认为这个进程“性价比低、该杀”。
-
oom_score_adj范围是 -1000(永不杀)到 +1000(优先杀),Redis 默认为 0;若宿主机上其他进程设了负值(如关键数据库),Redis 就更容易被选中 - 不要只看
free -h,它反映的是全局内存,而 OOM 可能发生在 cgroup 内部——用cat /sys/fs/cgroup/memory/memory.max(cgroup v2)或cat /sys/fs/cgroup/memory/redis.service/memory.limit_in_bytes(cgroup v1)确认 Redis 所在容器或服务的实际内存上限
持久化期间 CPU 和 I/O 正常,但 RSS 瞬间飙升
RDB fork 是写时复制(Copy-on-Write),子进程刚 fork 出来时并不立即复制全部内存页,但一旦父进程修改某页、或子进程开始读取某页,就会触发实际内存分配。所以真正危险的不是 fork 动作本身,而是 fork 后那一小段时间内的写入高峰。
典型诱因包括:
- 业务在 RDB 执行窗口期集中写入(比如整点刷新缓存)
- 启用了
save配置但未配stop-writes-on-bgsave-error no,导致上一次 RDB 失败后,后续写入被阻塞并积压,最终在下一次 fork 时集中爆发 - 使用了
appendonly yes且 AOF 重写(bgrewriteaof)与 RDB 同时发生,双重 fork 加剧内存压力
临时缓解可禁用自动 RDB(注释掉所有 save 行),改用定时脚本在低峰期手动触发 redis-cli bgsave,并确保两次之间留足内存回收时间。
vm.overcommit_memory 设置为 0 或 1 导致 fork 失败
Linux 内核对 fork 的内存预估取决于 /proc/sys/vm/overcommit_memory 的值:
-
0(默认):启发式判断,较保守,容易在内存紧张时拒绝 fork,报错Fork operation failed,但不会直接 OOM Kill -
1:总是允许 fork,哪怕物理内存不够——这正是多数 Redis OOM 场景的温床:fork 成功,但子进程一读页就触发 OOM Killer -
2:严格模式,按vm.overcommit_ratio和 swap 大小计算上限,最可控
生产环境强烈建议设为 2,并配合合理设置 vm.overcommit_ratio(如 80)和预留 swap(至少 2GB)。改完需执行 sysctl -w vm.overcommit_memory=2 并写入 /etc/sysctl.conf 持久化。
这个参数不起眼,却是很多“明明内存还有余量却莫名被杀”的根本原因——它决定了 fork 是被拦在门外,还是放进来再处决。











