事情本身不复杂,线索都在日志里。一台 16 核 64G 的 CentOS 7 跑 Redis 和 Java 混部,按调优文档把 transparent_hugepage 的 defrag 设成 always,之后接口每隔几秒出现一次百毫秒抖动。
第一反应是「Redis 的 fork 对延迟敏感,规整期间 fork 直接变慢」,验证下来不成立。
这类报错背后常见的原因有几处,逐个排除就行。always 让内核在分配时同步做内存规整,规整过程会暂停分配线程。也可能是规整要迁移页,跨 NUMA 节点的迁移成本更高,抖动被放大。
还有一种情况,内存碎片本身已经严重,强制规整只是把代价搬到分配路径上。
第一件事是看当前的 THP 策略
cat /sys/kernel/mm/transparent_hugepage/enabled /sys/kernel/mm/transparent_hugepage/defrag
再往下改成只在需要时规整
echo madvise > /sys/kernel/mm/transparent_hugepage/defrag
然后确认碎片情况再决定是否彻底关闭
cat /proc/buddyinfo && grep -i huge /proc/meminfo
等前面都确认过,再把策略写进开机脚本固化
printf 'echo madvise > /sys/kernel/mm/transparent_hugepage/defrag\n' > /etc/rc.d/init.d/thp.sh && chmod +x /etc/rc.d/init.d/thp.sh
改完先别撤,确认这几项。接口的 p99 抖动消失,/sys/kernel/mm/transparent_hugepage/defrag 显示 madvise,buddyinfo 中高阶块数量不再持续下降。
容易忽略的是,数据库和缓存类服务通常建议关掉 THP 或改成 madvise,但关了会增加 TLB miss,是否关要看基准测试,不能照抄别人的结论。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
