应通过numastat -p $(pgrep mysqld)查Heap行numa_hit占比(需>90%)、禁用transparent_hugepage、在systemd service中配置CapabilityBoundingSet和全路径numactl启动,并按负载类型选用--membind或--interleave策略。

确认mysqld实际运行在哪个NUMA节点
别信top或htop显示的CPU占用——它们不反映内存归属。真正要查的是进程绑定状态和页帧物理位置:
运行numactl --show看系统默认策略(通常是preferred或localalloc);
用cat /proc/$(pgrep mysqld)/status | grep -i "mem"只能辅助判断,关键要看numastat -p $(pgrep mysqld)输出;
重点盯Heap行的numa_hit占比:低于90%就说明Buffer Pool大量页帧落在远端节点;
如果numa_miss和numa_foreign持续高于5%,基本可断定InnoDB正在被远程内存“截胡”。
必须禁用transparent_hugepage
numactl --membind对大页无效,内核会绕过你的绑定策略直接从任意节点分配2MB页。不关它,其他所有操作都白搭:
检查状态:cat /sys/kernel/mm/transparent_hugepage/enabled,若输出含[always]或[madvise],必须改;
临时关闭:echo never > /sys/kernel/mm/transparent_hugepage/enabled;
永久生效:在/etc/default/grub的GRUB_CMDLINE_LINUX里加transparent_hugepage=never,再update-grub && reboot;
验证是否生效:grep AnonHugePages /proc/meminfo应为0。
systemd服务里正确配置numactl启动
直接在ExecStart=前加numactl会失败,错误通常是Operation not permitted或Cannot allocate memory:
必须在service文件中添加CapabilityBoundingSet=CAP_SYS_NICE CAP_SYS_RESOURCE;
禁用cgroup内存统计干扰:MemoryAccounting=false(尤其cgroup v1下,它会覆盖--membind);
启动命令必须写全路径:ExecStart=/usr/bin/numactl --cpunodebind=0 --membind=0 /usr/sbin/mysqld $MYSQLD_OPTS;
不要用mysqld_safe启动——它会覆盖numactl环境,改用直接调用mysqld二进制。
根据负载类型选--membind还是--interleave
--interleave=all看似省事,实则让Buffer Pool页帧随机散落各节点,InnoDB线程访问时仍可能触发跨节点访问:
单实例高吞吐(如OLTP主库):用numactl --cpunodebind=0 --membind=0,强制全部落在Node 0,前提是innodb_buffer_pool_size ≤ Node 0可用内存 × 0.8;
多实例或混合负载(如备库+ETL):用numactl --interleave=all,但必须同步调大innodb_buffer_pool_instances(建议≥ NUMA节点数);
绝对不要只靠--interleave all一招打天下——它不解决本地化问题,反而加剧抖动;
验证最终效果不能只看SHOW ENGINE INNODB STATUS,得用sudo cat /proc/$(pgrep mysqld)/numa_maps | awk '$NF ~ /heap/ {print $4}' | sort | uniq -c,输出里应几乎全是N0=或interleave:0。



















