Linux服务器NUMA架构性能调优:从内存分配到中断绑核

NUMA架构对服务器性能的影响

现代多路服务器普遍采用NUMA(Non-Uniform Memory Access)架构。以双路Intel Xeon或AMD EPYC服务器为例,每颗CPU有本地内存控制器,访问本地内存延迟约80ns,访问远端内存延迟则升至120-150ns。这个差距在高并发数据库、消息队列等内存密集型场景下会显著影响吞吐量。

通过numactl –hardware可以查看服务器的NUMA拓扑:

$ numactl --hardware
available: 2 nodes (0-1)
node 0 size: 128 GB
node 0 free: 42 GB
node 1 size: 128 GB
node 1 free: 38 GB
distances:
  0 1
  0 10 21
  1 21 10

distance矩阵中,10表示本地访问,21表示远端访问,数值越大延迟越高。双路系统差距约2倍,四路系统远端延迟可达3倍以上。

识别跨NUMA节点的内存访问

Linux内核提供了numastat工具统计每个NUMA节点的内存分配情况:

$ numastat -p mysqld

Per-node process memory usage (in MBs) for PID 1234 (mysqld)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0               0               0
Heap                      832             456            1288
Stack                       4               2               6
Private                   128              64             192
Total                     964             522            1486

如果Heap在两个节点上分布不均匀,且总内存远超单节点容量,说明进程大量访问远端内存。此时可以通过perf进一步确认:

$ perf stat -e numastat_node0,numastat_node1 -p 1234 sleep 10

Performance counter stats for process id 1234:
    1,234,567  numastat_node0  (本地节点命中)
      876,543  numastat_node1  (远端节点访问)
    2.11 seconds time elapsed

远端访问占比超过20%时,就需要考虑NUMA调优。

内存分配策略调优

Linux默认的NUMA内存分配策略是preferred(优先本地),但当本地内存不足时会自动分配远端内存。通过numactl可以精确控制:

# 绑定到NUMA节点0运行,仅在本地分配内存
numactl --cpunodebind=0 --membind=0 ./my_app

# 交错分配内存,适合内存均匀访问的场景
numactl --interleave=all ./my_app

# 优先本地分配,不足时允许远端(比默认更激进)
numactl --preferred=0 ./my_app

不同策略适用场景:

–membind:数据库、缓存服务,访问模式集中,严格限制在本地节点。
–interleave:科学计算、批量处理,内存访问模式均匀,追求整体带宽。
–preferred:Web应用、混合负载,兼顾本地优先和弹性分配。

中断绑核优化网络性能

网卡中断默认由内核调度到任意CPU处理,在NUMA架构下会导致中断处理和用户态数据分处不同节点,增加内存访问延迟。将网卡中断绑定到与用户进程相同的NUMA节点,可以显著降低延迟。

首先确认网卡所在的NUMA节点:

$ cat /sys/class/net/eth0/device/numa_node
0

# 如果返回-1,说明内核未正确识别NUMA亲和性,需手动设置

然后使用irqbalance或手动设置中断亲和性:

# 停止irqbalance服务
systemctl stop irqbalance

# 查看网卡中断号
$ grep eth0 /proc/interrupts
  45:  12345678   IO-APIC   45   eth0-TxRx-0
  46:   8765432   IO-APIC   46   eth0-TxRx-1
  47:   5432109   IO-APIC   47   eth0-TxRx-2

# 将中断绑定到NUMA节点0的CPU(假设为0-15,32-47)
echo 0xffff0000ffff > /proc/irq/45/smp_affinity
echo 0xffff0000ffff > /proc/irq/46/smp_affinity
echo 0xffff0000ffff > /proc/irq/47/smp_affinity

对于支持多队列的网卡(如Intel XL710),每个队列对应一个中断,建议将不同队列均匀绑定到NUMA节点的各个核心上,避免中断集中导致单核瓶颈。

KVM虚拟机的NUMA透传配置

在虚拟化环境中,Guest OS感知不到物理NUMA拓扑,可能导致vCPU跨节点调度。Libvirt支持NUMA透传:

<domain type='kvm'>
  <cpu mode='host-passthrough'>
    <topology sockets='2' dies='1' cores='16' threads='2'/>
    <numa>
      <cell id='0' cpus='0-31' memory='64' unit='GiB' memAccess='shared'/>
      <cell id='1' cpus='32-63' memory='64' unit='GiB' memAccess='shared'/>
    </numa>
  </cpu>
  <numatune>
    <memory mode='strict' nodeset='0,1'/>
    <memnode cellid='0' mode='strict' nodeset='0'/>
    <memnode cellid='1' mode='strict' nodeset='1'/>
  </numatune>
</domain>

numatune的strict模式确保vCPU的内存分配严格绑定到物理NUMA节点,避免跨节点访问。配合CPU的host-passthrough模式,Guest OS可以直接感知NUMA拓扑并做应用级优化。

内核参数调优建议

以下内核参数与NUMA行为相关,建议根据场景调整:

# 禁用内核的自动NUMA平衡(某些场景下反而增加开销)
kernel.numa_balancing = 0

# 大页内存分配到指定NUMA节点
echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages

# 调整vm.zone_reclaim_mode(1=本地内存回收优先)
vm.zone_reclaim_mode = 1

kernel.numa_balancing默认开启,内核会自动迁移进程内存到当前运行CPU所在的NUMA节点。对于绑定了CPU的应用(如数据库),这个机制会造成不必要的页面迁移开销,建议关闭。对于未绑定CPU的通用负载,保持开启可以降低远端访问概率。

NUMA调优不是一次性的工作,需要在部署前做好拓扑规划,在运行中持续监控numastat和perf指标,根据负载变化动态调整绑定策略。核心原则很简单:让数据和处理它的CPU在同一个NUMA节点上。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-numa-jia-gou-xing-neng-diao-you-cong-nei-cun/

(0)
小编小编
上一篇 22小时前
下一篇 22小时前

相关推荐