用过几年服务器的人,多少都被 NUMA、物理核、超线程这几个词绕昏过。尤其当你面对一台 96 核、192 线程的机器,想搞清楚某个进程到底跑在哪颗核上、内存访问为什么忽快忽慢、虚拟机吵着说 CPU 资源不够时,这些概念就不是笔试题目了,而是每天都要处理的真实问题。
这篇文章想做的就是把这几个概念彻底捋顺:NUMA 节点到底是什么,物理核和超线程核在操作系统里是怎么呈现的,三层拓扑之间是什么关系,以及你在实际运维中应该怎么查看、怎么绑定、怎么避坑。内容偏实践,但我会先把原理讲透,因为只背命令不搞懂内因,换台机器你就又懵了。
1. 整体设计与思路拆解:为什么现代服务器离不开 NUMA
1.1 NUMA 到底在解决什么问题
NUMA,全称 Non-Uniform Memory Access,非统一内存访问。它不是什么新概念,但在今天的大规模服务器里,它的存在感比以往任何时候都强。
先说它解决的核心矛盾:CPU 越来越多,内存访问速度跟不上。
想象一下这个场景。你有一块主板,上面插着 2 颗物理 CPU,每颗 CPU 有 32 个物理核,每个物理核支持 2 个超线程,总共 128 个逻辑核。如果所有 CPU 和所有内存都挂在一个共享总线或者一个统一内存控制器上,那么当很多核同时访问内存时,总线会成为瓶颈,延迟会急剧上升。物理距离越远,信号传输越慢,访问延迟就会越高。这是一种"物理法则",绕不过去。
于是 NUMA 出现了。它的思路很简单:把整台服务器划分成若干个节点,每个节点有自己的 CPU 集合和本地内存。节点内部的 CPU 访问本地内存,速度最快;访问其他节点的内存,速度和延迟都会差一截。这就是"Non-Uniform"的含义——同一个进程在不同节点上访问内存,性能表现得不一样。
从架构上来讲,每个 NUMA 节点实际上是一个独立的片上系统,它拥有独立的 DDR 内存通道和 PCIe 根控制器。节点之间通过高速互联总线通信。在一个双路服务器里,两颗 CPU 之间的互联,就是典型的 NUMA 链路。当我在日常运维中遇到某个数据库实例性能突然跳水,第一反应往往不是 CPU 不够用了,而是想确认它是不是跨 NUMA 节点访问内存了,这个判断方向的正确率非常高。
1.2 物理核、逻辑核、超线程核,这三个概念先分清
很多刚接触服务器的人最容易在这个地方绕晕。我先给一个最简化的公式:逻辑核数量 = 物理核数量 × 每核超线程数。
物理核指的是 CPU 这个物理封装里实实在在的运算核心,它是真正的硬件实体,拥有独立的计算单元、一级缓存和二级缓存。而操作系统里看到的 CPU 编号,比如 cpu0、cpu1、cpu2……这些叫逻辑核或者逻辑处理器。如果 CPU 不支持超线程,那么逻辑核数量和物理核数量一一对应;如果支持超线程,一个物理核会以两个逻辑核的形式暴露给操作系统。
超线程(Hyper-Threading)的技术本质,是让一个物理核内部有两条执行流。它不是一个物理核拆成两个用,而是让物理核内部的执行单元利用率更高。举个例子,一个物理核执行一段很依赖内存的指令,ALU(算术逻辑单元)可能闲着,这时候另一条线程就可以上来用 ALU 做计算。这两条线程共享物理核的计算资源、缓存和队列,好处是能轻微提升吞吐,坏处是它们"打架"时性能反而更差。
判断你的机器支持多少逻辑核,在 Linux 里最直接的就是 lscpu:
bash复制$ lscpu
Architecture: x86_64
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 32
Socket(s): 2
NUMA node(s): 4
NUMA node0 CPU(s): 0-31
NUMA node1 CPU(s): 32-63
NUMA node2 CPU(s): 64-95
NUMA node3 CPU(s): 96-127
注意看输出的几个关键字段:
Thread(s) per core: 2表示每个物理核开了 2 个超线程;Core(s) per socket: 32表示每颗物理 CPU 有 32 个物理核;Socket(s): 2表示有 2 颗物理 CPU;NUMA node(s): 4表示整机被划分成了 4 个 NUMA 节点。
这里有个细节容易忽略:2 颗 CPU、每颗 32 核,但 NUMA 节点是 4 个,而不是 2 个。这说明这台机器启用了某些平台特性,或者说每颗 CPU 内部的多个 Die(裸片)被独立划分成了 NUMA 节点。这是目前高端 CPU 的常见做法,比如某些型号的 32 核 CPU 内部实际上是 4 个 Die,每个 Die 拥有独立的内存控制器。此时"NUMA 节点数"不等于"CPU 颗数",你得按实际拓扑来规划业务部署。
1.3 内存访问的"因距离而异"到底能差多少
很多人对 NUMA 影响的理解停留在"跨节点会慢一点"这种模糊层面。实际数据会更有说服力。我在一台典型的双路服务器上测试过内存访问延迟,用 numactl --hardware 可以看到不同节点间的距离矩阵。
bash复制$ numactl --hardware
av
