MySQL / PostgreSQL NUMA 最佳实践
前提 双路服务器 / 中断亲和性 / NUMA,所以默认:2 Socket,NUMA node0 + node1,大内存场景
| 项目 | 必须 |
|---|---|
| CPU 运行在哪个 NUMA node | ✅ |
| 内存从哪个 NUMA node 分配 | ✅ |
| 磁盘 / 网卡 IRQ 在哪个 node | ✅ |
👉 任何一个错位,性能都会抖。
❌ 错误示例:
taskset -c 0-15 mysqld
- CPU 绑了
- 内存没绑
-> 100% 跨 NUMA
| 模式 | 适用 |
|---|---|
| 单 NUMA Node 绑定 | 单实例、内存 ≤ 单 node |
| NUMA interleave | 内存 > 单 node |
前提:
- MySQL 实例内存 ≤ 单 NUMA node 内存
启动方式
numactl --cpunodebind=0 --membind=0 mysqld
或 systemd:
[Service]
CPUAffinity=0-15
NUMAPolicy=local
MySQL 参数建议
innodb_buffer_pool_size = 90% of node memory
innodb_buffer_pool_instances = 8
适合场景
- OLTP
- 高 QPS
- 延迟敏感
前提:
- MySQL 内存 > 单 NUMA node
启动方式(官方推荐)
numactl --interleave=all mysqld
systemd:
NUMAPolicy=interleave
NUMAMask=0,1
为什么 interleave 好?
- 内存均匀分布
- 避免某个 node 被打满
- 稳定性 > 极限性能
innodb_numa_interleave = ON
📌 官方建议:用 numactl,不用 MySQL 内部实现
numactl --interleave=all
≠ BIOS 关闭 NUMA
(这是不同概念)
numastat -p $(pidof mysqld)
关键指标:
- local ≫ remote
- interleave 场景:node0 / node1 接近
PostgreSQL 对 NUMA 非常敏感,比 MySQL 更容易“翻车”。
PostgreSQL:宁可 interleave,也不要半 NUMA
启动方式
numactl --cpunodebind=0 --membind=0 postgres
systemd:
CPUAffinity=0-15
NUMAPolicy=local
PostgreSQL 参数
shared_buffers = 70% of node memory
work_mem = 控制总并发
numactl --interleave=all postgres
❌ 不要只绑 CPU
❌ 不要关闭 kernel.numa_balancing 再不绑内存
| 场景 | 设置 |
|---|---|
| MySQL | 关闭 |
| PostgreSQL | 关闭 |
echo 0 > /proc/sys/kernel/numa_balancing
- 中断在哪个 NUMA node
- DB 进程就跑在哪个 node
cat /proc/interrupts
- blk-mq 默认多队列
- NUMA 不一致 -> cache miss
MySQL
[Service]
CPUAffinity=0-15
NUMAPolicy=interleave
NUMAMask=0,1
PostgreSQL
[Service]
CPUAffinity=0-15
NUMAPolicy=local
lscpu
numactl --hardware
numastat
numastat -p mysqld
numastat -p postgres
| 数据库 | 推荐策略 |
|---|---|
| MySQL | interleave 或 单 NUMA |
| PostgreSQL | 单 NUMA > interleave |
| 两者 | 不要半 NUMA |
NUMA 调优不是“开或关”,而是:CPU、内存、IRQ 三者位置必须一致。