先确认Redis是否真被Swap换出:用redis-cli info取PID,再cat /proc/PID/status看Swap值是否>0;若为0则卡顿与Swap无关;再用smaps计算换出比例,超10%才算实质性Swap压力。

怎么确认 Redis 真的被 Swap 换出了
别一卡就关 Swap。先看事实:用 redis-cli info | grep process_id 拿到 PID,再执行 cat /proc/<pid>/status | grep -i swap</pid>——重点看 Swap: 这一行是否大于 0(不是 SwapPss)。如果为 0,说明卡顿跟 Swap 无关,调 vm.swappiness 是白忙。
进一步验证换出比例:cat /proc/<pid>/smaps | awk '/^Size:/ {size+=$2} /^Swap:/ {swap+=$2} END {printf "Size: %d MB, Swap: %d MB\n", size/1024, swap/1024}'</pid>。若 Swap 占 Size 超过 10%,才算有实质性 Swap 压力。
为什么设成 0 反而更危险
vm.swappiness=0 不等于禁用 Swap,它只是抑制“非必要”匿名页换出;但当物理内存彻底耗尽、page cache 也回收完时,内核仍可能 fallback 到 Swap(尤其在 5.8+ 内核),或直接触发 OOM Killer——而 redis-server 因 RSS 高,大概率第一个被杀。
真实风险案例:压测中执行 swapoff -a 后,maxmemory 还没触顶,Redis 就被 Out of memory: Kill process redis-server 杀掉。
生产环境更稳的选择是:vm.swappiness=1。它既大幅降低 COW 页被误换出的概率,又保留最后一道 Swap 缓冲,避免 OOM Killer 误伤。
swappiness 调低后还卡?大概率是 THP 在捣鬼
即使 vm.swappiness=1,若透明大页(THP)开着,fork() 会拷贝整块 2MB 页表,耗时从毫秒级跳到数百毫秒,且大页更容易被内核判定为“冷页”优先换出。
必须同步禁用 THP:
- 临时禁用:
echo never > /sys/kernel/mm/transparent_hugepage/enabled - 永久生效:不能只靠
/etc/default/grub加transparent_hugepage=never,某些内核版本不生效;推荐写入/etc/rc.local或 systemd service 的ExecStartPre - 验证是否真关掉:
grep -i "mmupage\|mmupf" /proc/$(pgrep redis-server)/smaps | head -5,输出里不能出现2048 kB,全是4 kB才算成功
NUMA 架构下 Swap 占用高,光调 swappiness 不够
双路 Xeon + NUMA 服务器上,Redis 主进程若被调度到 node 0,而该 node 本地内存已满,内核宁愿换出页到 Swap,也不跨 node 分配内存——这时 vm.swappiness=1 和 THP 关闭都无效。
解决方法是强制内存交错分配:
- 启动 Redis 前加:
numactl --interleave=all redis-server /path/to/redis.conf - 或改 systemd service,在
ExecStart前加ExecStartPre=/usr/bin/numactl --interleave=all true - 验证:
numastat -p $(pgrep redis-server),看各 node 的heap和mapped是否均匀
真正关键的不是“要不要 Swap”,而是让内核别把 Redis 的匿名页当成可牺牲品——这需要 swappiness、THP、NUMA 策略三者协同,缺一不可。单点调优容易白费功夫。


















