上一篇 下一篇 分享链接 返回 返回顶部

如何在香港裸金属服务器上通过NUMA优化与CPU亲和性配置提升高负载Web应用的处理能力?

发布人:Minchunlin 发布时间:2025-07-14 10:06 阅读量:616

昨天凌晨两点,香港机房突然传来告警:我们的主站 Web API 响应时间飙升,CPU 占用却并不满载。直觉告诉我这不是简单的资源瓶颈。调研之后我发现,部署在双路 Intel Xeon 服务器上的 Web 应用在高并发请求下存在 NUMA 跨节点内存访问导致的延迟抖动。同时,进程在系统中被随意调度,缺乏 CPU 亲和性的绑定,进一步放大了这种延迟。为了解决这个问题,我展开了一轮针对 NUMA 架构与 CPU 亲和性的系统级调优。以下是我在香港裸金属服务器上实践的全过程。

一、服务器硬件与应用架构概况

服务器位置:香港新界 Telehouse 高密度机柜

  • 型号:Dell PowerEdge R7525
  • CPU:2 x AMD EPYC 7543(共 64 核心,128 线程,2 NUMA 节点)
  • 内存:512GB DDR4 ECC(按 NUMA 节点平均分布)
  • 操作系统:Rocky Linux 8.9,内核 5.14
  • Web应用:多进程 Nginx + uwsgi + Python Flask,使用大量本地内存缓存与Redis交互

二、NUMA 架构原理回顾与风险点分析

NUMA 架构特性:

  • 每颗 CPU(或 Socket)对应一个 NUMA 节点,每个节点拥有本地内存。
  • 进程如果访问非本地内存,会产生 远程内存访问延迟(remote access latency)。
  • Linux 默认调度器未必将进程和其内存放在同一 NUMA 节点。

风险分析:

  • 进程分布不均衡:多个 Nginx/uwsgi worker 被调度到不同 NUMA 节点,造成非本地内存访问。
  • 内存未绑定节点:Flask 启动后从默认节点分配内存,不受控。
  • 中断负载不平衡:NIC 中断集中在 NUMA-0 上,流量经过 CPU0 处理,但处理线程却在 NUMA-1。

三、实战步骤:NUMA与CPU亲和性联合调优

1.确定 NUMA 拓扑结构

lscpu | grep -i numa
numactl --hardware

输出示例:

available: 2 nodes (0-1)
node 0 cpus: 0-31
node 1 cpus: 32-63
node 0 size: 256000 MB
node 1 size: 256000 MB

2. 固定进程的 CPU 亲和性与内存节点(Nginx/uwsgi)

我将 Nginx 和 uWSGI 分别部署两组,每组绑定到一个 NUMA 节点:

# 绑定 Nginx + uWSGI 到 NUMA node 0(核心 0-31)
numactl --cpunodebind=0 --membind=0 /usr/sbin/nginx -c /etc/nginx/nginx-node0.conf
numactl --cpunodebind=0 --membind=0 /usr/local/bin/uwsgi --ini uwsgi-node0.ini &

# 绑定第二组到 NUMA node 1(核心 32-63)
numactl --cpunodebind=1 --membind=1 /usr/sbin/nginx -c /etc/nginx/nginx-node1.conf
numactl --cpunodebind=1 --membind=1 /usr/local/bin/uwsgi --ini uwsgi-node1.ini &

3. 优化 uwsgi 配置中的线程/进程分布

# uwsgi-node0.ini
processes = 16
threads = 2
cpu-affinity = 0-31

# uwsgi-node1.ini
processes = 16
threads = 2
cpu-affinity = 32-63

4. 配置 NIC 中断亲和性,减少 NUMA 跨节点 IO

# 查看中断绑定 CPU
cat /proc/interrupts | grep -i eth

# 使用 `irqbalance` 固定某些 NIC IRQ 到对应 NUMA 节点核心
echo 00000000,ffffffff > /proc/irq/XXX/smp_affinity

或者禁用 irqbalance,手动绑定:

systemctl stop irqbalance
for irq in $(grep eth0 /proc/interrupts | awk '{print $1}' | sed 's/://'); do
  echo ffffffff > /proc/irq/$irq/smp_affinity
done

5. 设置内存页策略(防止页漂移)

# 避免页面随意迁移:madvise + numa balancing off
echo 0 > /proc/sys/kernel/numa_balancing

# 设置 uWSGI 进程为 interleave 分配(仅特定需要多 NUMA 模式)
numactl --interleave=all uwsgi ...

四、验证与性能对比分析

对比配置前后性能(wrk 测试):

测试项 默认调度器 NUMA+CPU绑定优化
平均响应时间(ms) 23.4 14.7
P95响应(ms) 57.8 21.2
最大并发支持数 6800 9800
CPU使用率差异 不均衡 两节点均衡50%

内核页迁移统计:

grep -i numa /proc/vmstat | grep -E 'migrations|local|remote'

# 优化后 remote_pages 值显著下降,remote->local 提高命中率

五、后续建议与补充优化方向

结合 cgroup v2 实现进程与NUMA节点的层级管控,确保资源配额不被打破。

内核参数调优:

sched_domain.cpu0.domain0.flags=524289

kernel.numa_balancing=0

结合业务指标联动:将 CPU 核心的温度与负载指标接入 Prometheus,动态微调 affinity。

容器化部署场景下:推荐使用 --cpuset-cpus 和 --cpuset-mems 控制容器的 NUMA 节点亲和性。

在这次优化过程中,我深刻体会到即使拥有强大硬件,如果忽视了 NUMA 结构与 CPU/内存调度机制,也会使 Web 应用性能陷入瓶颈。通过手动绑定进程到对应 NUMA 节点、合理配置 CPU 亲和性、优化中断分配,我们将原本抖动明显的高并发应用变得稳定且高效。这类调优并非一次性工作,而是应随业务扩展不断演进的持续工程。对于部署在香港的数据中心而言,尤其面向全球高并发访问,NUMA 与 CPU 拓扑感知的配置是不可或缺的基础设施优化环节。

目录结构
全文