服务器NUMA架构调优实战:跨节点内存访问延迟的定位与消除方案

NUMA(Non-Uniform Memory Access)是多路服务器的默认内存架构。双路EPYC 9004系列CPU每颗处理器有自己的本地DDR5内存控制器,本地内存访问延迟约80ns,跨NUMA节点访问要走Infinity Fabric互联总线,延迟升至130ns以上,带宽减半。数据库、消息队列这类内存密集型应用在NUMA配置不当的场景下,性能损失20%到50%的情况并不少见,问题往往出在线程与内存的节点绑定策略上。

NUMA拓扑信息查看与lscpu命令输出解读

动手调优前需要先确认机器的真实拓扑。lscpu命令输出里的NUMA相关字段:

lscpu | grep -i numa
# NUMA node(s):          2
# NUMA node0 CPU(s):     0-63,128-191
# NUMA node1 CPU(s):     64-127,192-255
# NUMA node0 memory:     0-1023G
# NUMA node1 memory:     1024-2047G

每个物理核在两个NUMA节点各有一组逻辑核(超线程),编号被切开是BIOS把超线程对分别映射到不同节点的结果。numactl –hardware能列出每个节点的内存总量、空闲量与节点距离:

numactl -H
# available: 2 nodes (0-1)
# node 0 cpus: 0 1 2 ... 63
# node 0 size: 102749 MB
# node 0 free: 98021 MB
# node 1 size: 102748 MB
# node 1 free: 99012 MB
# distances:
# node   0   1
#   0:  10  20
#   1:  20  10

距离值10是本地,20是远端,这个比值越大说明跨节点代价越高。用numastat命令看应用是否发生了跨节点分配:

numastat -p $(pidof mysqld)
# Per-node process memory usage (in MBs)
# Node 0          Node 1  Total
# Heap:         8123       214    8337
# Foreign:                     # 跨节点统计
# numa_hit:   9123000   1203000
# numa_miss:   231000   1450000   # miss越高说明内存分配错节点越多

numa_miss远高于本地命中率时,就是跨节点访问拖慢了应用,需要干预内存分配策略。

numactl绑定策略与内存分配模式配置

numactl是调整进程NUMA行为最直接的工具,四个常用参数覆盖了绝大多数场景:

# 场景1:进程与内存全部绑在节点0(数据库单实例常用)
numactl --cpunodebind=0 --membind=0 /usr/local/mysql/bin/mysqld

# 场景2:CPU允许全部节点,内存优先本地分配,不足时允许远端
numactl --interleave=all ./app

# 场景3:只绑定内存节点,CPU浮动
numactl --membind=1 ./app

# 场景4:交叉分配内存,均摊到所有节点(大内存应用防热点)
numactl --interleave=all java -Xms64g -Xmx64g -jar app.jar

参数选择的原则:CPU密集型应用用cpunodebind加membind成对绑定,保证线程与数据同节点;内存占用超过单节点容量的应用用interleave=all,否则后半段内存必然跨节点,不如均摊;网卡中断处理要注意,IRQ亲和性若绑在节点0而收包缓冲区(skb)在节点1分配,每个数据包都产生跨节点拷贝,用ethtool配合irqbalance把网卡队列中断绑到接收进程所在节点。

Kubernetes与数据库场景的NUMA对齐实践

容器化环境里NUMA问题更隐蔽。kubelet的静态CPU管理策略(static policy)配合CPU Manager能保证独占CPU池,但内存与设备对齐需要Topology Manager。kubelet配置示例:

# /var/lib/kubelet/config.yaml
cpuManagerPolicy: static
topologyManagerPolicy: single-numa-node
reservedSystemCPUs: 0,1
# 加上SR-IOV/dpdk等插件时设备亲和性一起对齐

topologyManagerPolicy设为single-numa-node后,Pod请求的CPU、内存与SR-IOV网卡会被调度到同一NUMA节点,NFV与低延迟交易类负载必须开启这一项。策略取值从严到松依次是none、best-effort、restricted、single-numa-node,后两者会在资源无法满足时拒绝调度,生产上用restricted起步观察Admit失败率再收紧。

数据库场景的实测参考:MySQL 8.0在双路服务器上跑只读QPS压测,进程未绑定时numa_miss占比31%,QPS约18万;用numactl –cpunodebind=0 –membind=0绑定到单节点(牺牲一半CPU核心数)后QPS反而升到24万,本地命中率达98%。原因是InnoDB缓冲池热点页访问延迟下降,跨节点一致性流量消失。Redis这类单线程内存敏感服务更明显,绑定正确节点后P99延迟下降可达两成。调优完成后把numactl写入systemd服务单元的ExecStart,避免重启后策略丢失:

# /etc/systemd/system/redis.service 片段
ExecStart=/usr/bin/numactl --cpunodebind=1 --membind=1 /usr/bin/redis-server

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/fu-wu-qi-numa-jia-gou-diao-you-shi-zhan-kua-jie-dian-nei/

(0)
小编小编
上一篇 51分钟前
下一篇 51分钟前

相关推荐