Redis bgsave卡顿且rdb_last_bgsave_time_sec飙升至2~5s(正常≤0.1s)是THP干扰最直接信号:启用THP后fork触发的写时复制需拷贝2MB大页而非4KB,COW开销放大512倍,导致INCR/SET等命令进慢日志;须同时将enabled与defrag设为never、验证smaps无2048kB页、重启Redis生效。

Redis bgsave卡顿且rdb_last_bgsave_time_sec飙升到秒级
这是THP干扰最直接的信号。Redis执行bgsave时会fork()子进程,而启用THP后,内核用2MB大页管理内存,导致写时复制(COW)开销被放大512倍——哪怕主线程只改一个字节,也要拷贝整张2MB页。结果就是rdb_last_bgsave_time_sec从正常≤0.1s跳到2~5s,同时客户端明显感知到GET/SET延迟毛刺。
别只看INFO输出,必须验证:
- 运行
redis-cli info persistence | grep rdb_last_bgsave_time_sec,持续观察该值是否周期性突增(如每12~15分钟一次) - 若突增,立刻查
slowlog get 10,里面大量INCR、SET进慢日志(阈值设10ms),基本可锁定THP -
strace -p $(pgrep redis-server) -e trace=fork,write能看到fork()返回后紧跟着大量高延迟write调用
检查/sys/kernel/mm/transparent_hugepage/enabled和defrag是否真为never
很多团队只改了enabled,却漏掉defrag。只要defrag是[always]或[madvise],后台线程khugepaged就会持续扫描合并小页,照样卡Redis。
必须两个都查:
-
cat /sys/kernel/mm/transparent_hugepage/enabled→ 必须输出[never] -
cat /sys/kernel/mm/transparent_hugepage/defrag→ 同样必须是[never] - RHEL/CentOS 6+用户额外检查
/sys/kernel/mm/redhat_transparent_hugepage/enabled,路径不同但效果一样 - 容器或云主机还要防
tuned服务偷偷重开:运行systemctl is-active tuned,若为active,得sudo tuned-adm off && systemctl disable tuned
验证Redis进程smaps里是否还有2048 kB页
即使cat显示[never],也不能信。某些Java或MySQL启动脚本会悄悄调用madvise(MADV_HUGEPAGE),让THP在单个进程内生效。Redis主进程的/proc/<pid>/smaps</pid>才是最终证据。
操作步骤:
- 用
ps aux | grep redis-server拿到PID - 执行
grep -i "mmupage\|mmupf" /proc/<pid>/smaps | head -10</pid> - 正常应全是
MMUPageSize: 4 kB;若出现MMUPageSize: 2048 kB,说明THP仍在生效 - 顺手检查
cat /proc/<pid>/status | grep AnonHugePages</pid>,非零值也代表THP活跃
临时禁用THP仅用于验证,重启Redis才真正生效
临时关THP命令(需root):
echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag
但这只是运行时开关,系统重启或Redis重启后失效。更重要的是:Redis必须重启才能让fork避开THP——因为fork行为依赖进程启动时的内存页状态,不重启,旧的页表结构照旧走大页路径。
持久化方案因系统而异:
- CentOS 7+/Ubuntu 18.04+:用
systemd建/etc/systemd/system/disable-thp.service,开机自启 - 旧版CentOS 6/7:若
/etc/rc.local可用,加两行echo并chmod +x - GRUB级禁用(最彻底):在
/etc/default/grub的GRUB_CMDLINE_LINUX里加transparent_hugepage=never,再update-grub && reboot
最容易被忽略的一点:Kubernetes Pod或Docker容器里,/sys常被挂为只读,echo never会失败;此时必须在宿主机层禁用,或用securityContext.sysctls(v1.22+)透传配置。


















