目录一、处理器拓扑结构NUMA 和SMP1.1、SMPSymmetric Multi-Processing对称多处理1.2、NUMANon-Uniform Memory Access非一致性内存访问1.3、SMP 与 NUMA 关键对比1.4、现代系统的实际情况二、调度域和调度组2.1、 核心概念详解2.2、 实例演示双路 NUMA 服务器2.3、 如何查看系统中的调度域一、处理器拓扑结构NUMA 和SMP在多处理器系统中SMP对称多处理和NUMA非一致性内存访问是两种核心的硬件架构设计它们决定了 CPU 如何访问内存以及系统如何扩展。下面将对两者进行详细解析和对比。1.1、SMPSymmetric Multi-Processing对称多处理1. 核心思想SMP 是最传统的多处理器架构。其核心特点是所有 CPU 完全平等没有主从之分。共享统一内存所有 CPU 通过一条共享总线连接到同一块物理内存。统一内存访问 (UMA)任何 CPU 访问内存中任意地址的延迟和带宽都相同。2. 架构图------- ------- ------- | CPU 0 | | CPU 1 | | CPU N | ------- ------- ------- \ | / \ | / \ | / \ | / ---------- | 共享总线 | ---------- || ----------- | 统一内存 | -----------3. 优点架构简单硬件和操作系统设计相对容易。编程模型简单程序员无需关心数据在内存中的具体位置所有内存访问都是透明的。4. 缺点与瓶颈可扩展性差随着 CPU 数量的增加所有 CPU 都要争抢同一条共享总线来访问内存。内存带宽瓶颈总线的带宽是有限的当 CPU 数量增多时内存带宽成为系统性能的严重瓶颈。不适合大规模系统通常只适用于 CPU 核心数较少如 2-8 核的系统。1.2、NUMANon-Uniform Memory Access非一致性内存访问1. 核心思想NUMA 是为了解决 SMP 的可扩展性问题而诞生的。其核心特点是节点化Node-based系统被划分为多个节点Node。每个节点包含一组 CPU 核心 本地内存Local Memory。非一致性内存访问本地访问Local AccessCPU 访问自己所在节点的内存延迟低、带宽高。远程访问Remote AccessCPU 访问其他节点的内存需要通过高速互连总线如 Intel UPI, AMD xGMI延迟高、带宽低。2. 架构图---------------------- ---------------------- | Node 0 | | Node 1 | | --------------- | | --------------- | | | CPU0 | CPU1 | | | | CPU 2 | CPU3 | | | --------------- | | --------------- | | | | | | | | -------------- | | --------------- | | | 本地内存 A |---|------|-| 本地内存 B | | | -------------- | 互连 | -------------- | ---------------------- 总线 ----------------------3. 优点高可扩展性通过增加节点可以轻松扩展 CPU 和内存容量避免了单一总线的瓶颈。更高的内存带宽每个节点都有自己的内存控制器和通道总内存带宽随节点数线性增长。适合大规模系统现代服务器、数据库、HPC高性能计算集群普遍采用 NUMA 架构。4. 缺点与挑战架构复杂硬件和操作系统特别是调度器和内存管理器的设计更复杂。编程模型复杂为了获得最佳性能应用程序需要具备 NUMA 意识NUMA-aware尽量让进程在其本地内存上分配和访问数据避免昂贵的远程访问。性能不均衡如果负载分配不当可能会导致某些节点过载而其他节点空闲且跨节点通信开销大。1.3、SMP 与 NUMA 关键对比表格特性SMP (对称多处理)NUMA (非一致性内存访问)内存访问统一 (UMA)所有 CPU 访问内存延迟/带宽相同非统一本地访问快远程访问慢可扩展性差受限于共享总线带宽好可通过增加节点线性扩展适用场景小型服务器、桌面电脑核心数少大型服务器、数据中心、HPC核心数多硬件复杂度低高瓶颈内存总线带宽跨节点通信延迟1.4、现代系统的实际情况“纯” SMP 已罕见即使是普通的消费级多核 CPU如 Intel i7, AMD Ryzen其内部也采用了类似 NUMA 的设计。例如一个 CPU 封装内可能有多个 CCXCore ComplexCCX 之间通过 Infinity Fabric 或 Ring Bus 互联访问不同 CCX 的 L3 缓存或内存控制器会有微小的延迟差异。但在操作系统层面通常仍将其视为一个 NUMA 节点即 numactl --hardware 显示只有一个 node。真正的 NUMA 系统主要出现在双路2P、四路4P甚至更多路的服务器上。在这些系统中每个物理 CPU 插槽通常对应一个 NUMA 节点。如何查看 Linux 系统的 NUMA 拓扑# 安装 numactl 工具 sudo apt-get install numactl # Debian/Ubuntu sudo yum install numactl # RHEL/CentOS# 查看 NUMA 节点信息 numactl --hardware# 查看详细的 CPU 和内存拓扑 lscpu二、调度域和调度组在 Linux 内核中调度域Scheduling Domain, SD和调度组Scheduling Group, SG是调度器Scheduler用来管理多核 CPU 负载均衡的核心数据结构。它们将系统中的所有 CPU 核心按照物理拓扑结构如超线程、多核、NUMA 节点等组织成一个层次化的树状结构以便高效地进行任务迁移和负载平衡。以下是对这两个概念的详细解析及举例2.1、 核心概念详解调度域 (Scheduling Domain, SD)定义调度域是 CPU 拓扑结构中某一层级的逻辑集合。它代表了一组共享某些硬件资源如 L2/L3 缓存、内存控制器的 CPU。作用调度器在进行负载均衡时会优先在较小的调度域内寻找空闲 CPU 或迁移任务以减少跨域迁移带来的性能开销如缓存失效、内存访问延迟。特性层次化系统由多个层级的调度域组成例如SMT 级 - Core 级 - NUMA 级 - System 级。重叠性不同层级的调度域可以重叠。一个 CPU 可以同时属于 SMT 域、Core 域和 NUMA 域。属性每个调度域都有特定的标志位flags定义该域内的负载均衡策略例如是否允许跨域迁移、是否开启负载均衡等。调度组 (Scheduling Group, SG)定义调度组是调度域内的基本调度单元。在一个特定的调度域层级中CPU 被划分为若干个互不重叠的组。作用调度组是负载均衡算法直接操作的对象。调度器统计的是“组”的负载而不是单个 CPU 的负载。当某个组负载过高时调度器会尝试将任务迁移到同一调度域内负载较低的另一个组中。特性互斥性在同一个调度域层级内调度组之间是互斥的不重叠。一个 CPU 在该层级只能属于一个调度组。从属关系一个调度组从属于一个特定的调度域。包含关系一个调度组通常包含一个或多个 CPU或者是下一层级的调度域。SD 与 SG 的关系包含关系一个调度域包含一个或多个调度组。视角差异调度域定义了“在哪里”进行负载均衡范围。调度组定义了“谁”参与负载均衡实体。链表结构同一 CPU 在不同层级的调度域通过 parent/child 指针连接成垂直的双向链表。同一调度域内的所有调度组通过 next 指针连接成水平的单向链表。2.2、 实例演示双路 NUMA 服务器假设我们有一台服务器配置如下2 个 NUMA 节点 (Node 0, Node 1)每个节点有 2 个物理 CPU (Socket)每个 CPU 有 4 个核心 (Core)每个核心支持 2 线程 (SMT/Hyper-Threading)总逻辑 CPU 数 2 * 2 * 4 * 2 32 个逻辑 CPU (CPU 0 - CPU 31)拓扑结构与调度域/组划分Linux 调度器会建立如下层次结构从下往上表格层级 (Level)名称描述调度域 (SD) 示例调度组 (SG) 示例Level 0SMT共享 L1/L2 缓存的兄弟线程SD_SMT: 包含 CPU {0, 1}SG_0: {CPU 0},SG_1: {CPU 1}(注在 SMT 层通常每个线程视为一个组或者整个 SMT 对视为一个组具体取决于内核版本和配置通常是为了平衡兄弟线程间的负载)Level 1MC(Multi-Core)共享 L3 缓存的物理核心SD_MC: 包含 CPU {0, 1, 2, 3, 4, 5, 6, 7} (即 Socket 0 的第一个 CPU 的所有核)SG_Core0: {0, 1},SG_Core1: {2, 3} ...(每个物理核心及其线程构成一个组)Level 2DIE/PKG同一个物理封装 (Socket)SD_PKG: 包含 CPU {0...15} (整个 Socket 0)SG_CPU0: {0..7},SG_CPU1: {8..15}(每个物理 CPU 芯片作为一个组)Level 3NUMA共享本地内存的节点SD_NUMA: 包含 CPU {0...31} (如果是单 NUMA) 或 {0...15} (如果是双 NUMA 隔离)SG_Node0: {0..15},SG_Node1: {16..31}(每个 NUMA 节点作为一个组)Level 4SYSTEM整个机器SD_SYSTEM: 包含所有 CPU {0...31}SG_All: {0..31} (通常作为顶层兜底)(注实际内核中的层级名称可能略有不同如 SD_SIBLING, SD_CORE, SD_NUMA 等)负载均衡过程举例假设CPU 0上的负载非常高而CPU 2很空闲。SMT 层级检查调度器查看 CPU 0 所在的 SMT 调度域包含 CPU 0 和 CPU 1。发现兄弟线程 CPU 1 也很忙。无法在 SMT 组内平衡。MC (多核) 层级检查调度器向上遍历到 MC 调度域包含 CPU 0-7。在这个域内它将 CPU 分组为 SG_Core0 ({0,1}), SG_Core1 ({2,3}) 等。发现 SG_Core0 负载高SG_Core1 负载低。决策将 CPU 0 上的一个进程迁移到 CPU 2 上。优势因为 CPU 0 和 CPU 2 在同一个物理 CPU 内共享 L3 缓存迁移成本低缓存命中率损失小。NUMA 层级检查如果 MC 层无法平衡假设 Socket 0 (CPU 0-15) 全部都很忙而 Socket 1 (CPU 16-31) 空闲。调度器在 NUMA 调度域发现 SG_Node0 负载高SG_Node1 负载低。决策将任务迁移到 CPU 16。代价这是一个跨 Socket 甚至跨 NUMA 节点的迁移。虽然平衡了负载但新任务访问原内存数据时可能会发生远程内存访问Remote Memory Access延迟较高。调度器会权衡这种开销。2.3、 如何查看系统中的调度域在 Linux 系统中可以通过/proc/sys/kernel/sched_domain/目录查看当前系统的调度域配置需要 root 权限且内核开启了相关 proc 接口较新内核可能在/sys/devices/system/cpu/下# 查看 CPU 0 的调度域层级 ls /sys/devices/system/cpu/cpu0/topology/ --------------------------------------------------- # 查看具体的调度域参数 (如果内核支持) # 注意不同发行版和内核版本路径可能不同 find /proc/sys/kernel/sched_domain/ -name cpu0 #更直观的工具是使用 lstopo (来自 hwloc 包) 查看物理拓扑这直接对应了调度域的构建基础 lstopo --no-io总结调度域 (SD) 是地图划定了负载均衡的“搜索范围”遵循硬件拓扑以减少开销。调度组 (SG) 是玩家是负载均衡算法中实际承载负载并参与比较的“单位”。这种机制确保了 Linux 在多核、多路、NUMA 架构下既能充分利用所有 CPU 资源又能尽可能让进程运行在离数据最近的地方缓存亲和性与内存局部性。