redis主进程被阻塞多因rdb生成或aof重写时fork()引发的cow内存带宽争用及io干扰;需通过info persistence和latency doctor定位,用cpuset+cgroups隔离cpu并禁用swap、调优vm.swappiness与thp。

Redis持久化卡主进程?先看是哪类持久化在拖慢
Redis主进程被阻塞,90%以上情况出在 RDB 生成或 AOF 重写时的 fork() 调用和后续 IO。fork() 本身不耗时,但之后子进程复制页表、触发写时复制(COW)会大量占用内存带宽;而 AOF 重写期间若开启 aof-rewrite-incremental-fsync yes,虽能缓解,但默认是关闭的。
关键判断点:INFO persistence 中查看 rdb_bgsave_in_progress 或 aof_rewrite_in_progress 是否为 1,再结合 latency doctor 看是否有 command 或 fork 类型延迟 spike。
绑定CPU核心前必须确认:Linux调度器是否已让Redis“独占”
单纯用 taskset 绑核不解决问题——如果 Redis 进程和后台持久化子进程跑在同一 CPU 上,子进程的 IO 等待仍会抢占调度时间片,导致主线程响应变慢。
- 用
ps -o pid,psr,comm -C redis-server查看主线程运行在哪颗 CPU(psr列) - 用
ps -o pid,ppid,psr,comm -C redis-server找出 fork 出来的子进程(ppid 是主进程 pid),确认它们是否被调度到其他 CPU - 若子进程也落在同一 core,说明内核调度未隔离,此时绑核只是自我安慰
真正有效的CPU隔离:用cpuset + cgroups v1(非systemd)
Linux 的 cgroups v1 cpuset 控制器才能强制将主进程和子进程限定在指定 CPU 集合,且禁止跨集调度。systemd 的 CPUAffinity 只作用于启动时,对 fork 出的子进程无效。
实操步骤:
- 创建 cpuset:
mkdir /sys/fs/cgroup/cpuset/redis-main - 分配独占 CPU(如仅用 CPU 2):
echo 2 > /sys/fs/cgroup/cpuset/redis-main/cpuset.cpus - 禁止内存迁移(避免 NUMA 跨节点访问):
echo 0 > /sys/fs/cgroup/cpuset/redis-main/cpuset.mems - 把 Redis 主进程移入:
echo <code>PID> /sys/fs/cgroup/cpuset/redis-main/tasks
注意:该操作需 root 权限,且要确保 CPU 2 不被其他高负载进程(如数据库、监控 agent)共享。
IO干扰比CPU更隐蔽:禁用swap + 调整vm.swappiness
即使 CPU 隔离了,若系统内存吃紧触发 swap,Redis 进程页被换出,fork 后子进程一碰 COW 就得从磁盘换入,直接卡死数秒——这比绑核失效还难排查。
- 检查是否启用 swap:
swapon --show,生产环境应为无输出 - 临时禁用:
swapoff -a;永久禁用需注释/etc/fstab中 swap 行 - 降低交换倾向:
echo 1 > /proc/sys/vm/swappiness(Redis 推荐值,非 0,否则 OOM killer 更激进) - 搭配使用
echo never > /sys/kernel/mm/transparent_hugepage/enabled,防止 THP 导致 fork 延迟飙升
这些参数不写进 /etc/sysctl.conf 就只是临时生效,重启后回归默认,容易被忽略。









