必须用numactl显式绑定且--interleave=all多数情况下更差;需通过numastat -p查mysqld的numa_hit(应>90%)、禁用transparent_hugepage、按负载选--membind或--interleave策略,并在systemd中配置capabilityboundingset权限。

必须用 numactl 显式绑定,且默认的 --interleave=all 多数时候反而更差。
查清 mysqld 实际落在哪个 NUMA 节点上
别信 top 或 htop 显示的 CPU 占用——它们不反映内存物理归属。真正要看的是进程运行时的内存落点:
- 运行
numastat -p $(pgrep mysqld),重点盯Heap行的numa_hit:低于 90% 就说明大量 Buffer Pool 页帧在远端节点 -
numa_miss和numa_foreign同时高于 5%,基本可断定线程在 Node 0 执行,但数据在 Node 1 - 用
cat /proc/$(pgrep mysqld)/numa_maps | grep heap看实际分配:如果出现大量N1=或interleave:1,说明内存没集中
禁用 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
根据负载类型选对 numactl 绑定策略
--interleave=all 不是银弹,它只是轮询分配,不解决本地化访问问题,反而让 InnoDB 线程频繁跨节点取页:
- 单实例高吞吐(如 OLTP 主库):
numactl --cpunodebind=0 --membind=0,前提是innodb_buffer_pool_size≤ Node 0 可用内存 × 0.8 - 多实例或混合负载(如备库 + ETL):
numactl --interleave=all,但必须同步调大innodb_buffer_pool_instances(建议 ≥ NUMA 节点数) - 绝对不要在 systemd service 里只写
ExecStart=numactl mysqld:systemd 默认禁止CAP_SYS_NICE,会导致Operation not permitted - 正确写法:
ExecStart=/usr/bin/numactl --cpunodebind=0 --membind=0 /usr/sbin/mysqld $MYSQLD_OPTS,并加CapabilityBoundingSet=CAP_SYS_NICE CAP_SYS_RESOURCE
别忽略线程亲和性与本地内存耗尽的连锁反应
即使绑定了内存,线程仍可能被调度到远端节点执行,导致“人在 Node 0,数据在 Node 0,但线程在 Node 1”:
- 用
pidstat -t -p $(pgrep mysqld) 1 5观察migrate字段,每秒迁移 >3 次就说明线程在漂移 - 临时缓解可用
taskset -c 0-15 mysqld强制 CPU 绑定,再配合numactl内存绑定 - 若 Node 0
numa_free接近 0 而 Node 1 还有大量空闲,Linux 可能触发隐性 swap:查cat /proc/meminfo | grep -i "swap\|reclaim",持续增长就是信号 - 此时需配合
echo 1 > /proc/sys/vm/zone_reclaim_mode关闭单节点强制回收(仅在--membind下有效)
真正难的不是命令怎么写,而是得同时盯住 numastat 输出、numa_maps 分布、transparent_hugepage 状态和 systemd 权限配置这四件事——漏掉任何一环,优化就等于没做。











