当前位置: 首页 > news >正文

Linux内存管理章节十六:非均匀的内存访问:深入Linux NUMA架构内存管理

引言

在传统的SMP(对称多处理)系统中,所有CPU核心通过一条共享总线访问同一块内存,所有内存访问延迟是均匀的(UMA)。然而,随着CPU核心数量的增加,共享总线成为了巨大的性能和 scalability 瓶颈。为了解决这个问题,NUMA(Non-Uniform Memory Access,非统一内存访问) 架构应运而生。它带来了更高的可扩展性,但也引入了新的复杂性:内存访问速度取决于内存相对于执行CPU的位置。Linux内核必须感知并优化这种架构差异,否则性能将急剧下降。本文将解析NUMA的特点、内核的亲和性调度策略以及跨节点访问的优化手段。

一、 NUMA架构特点:距离产生延迟

NUMA架构的核心思想是将大量处理器分组,每个组成为一个节点(Node)。每个节点包含:

  • 一组CPU核心(通常是一个物理CPU插槽或多个核心的集合)
  • 一片本地内存(Local Memory)
  • 一个内存控制器集成在节点内

节点之间通过高速互连(如Intel的QPI、AMD的Infinity Fabric)连接。

关键特性:
  1. 访问延迟不对称

    • 本地访问(Local Access):CPU访问其所属节点的本地内存,路径最短,速度最快,延迟最低
    • 远程访问(Remote Access):CPU访问其他节点的内存,必须通过节点间互连,速度较慢,延迟更高(通常比本地访问慢1.5到2倍甚至更多)。
  2. 访问带宽不对称

    • 每个节点的本地内存带宽是独享的。
    • 节点间互连的总带宽是有限的,并且被所有节点共享。频繁的远程访问会饱和互连带宽,成为系统瓶颈。

对操作系统的影响:内核的内存分配策略不能再是“随便找一块空闲内存”。它必须尽量保证一个进程所使用的内存,其“归属”与运行该进程的CPU所在节点一致,即遵循节点亲和性(Node Affinity),否则应用程序将遭受性能损失。

二、 节点亲和性调度:将进程绑定在家门口

Linux内核提供了一套强大的机制来保证NUMA亲和性,其目标是 “尽量让任务在分配内存的同一个节点上运行,并尽量在任务运行的节点上为其分配内存”

1. 自动的NUMA平衡

现代Linux内核(CONFIG_NUMA_BALANCING)包含一个重要的后台特性——自动NUMA平衡

  • 工作原理
    1. 跟踪:内核周期性地标记进程的页表项为“未访问”(清除Accessed位)。
    2. 扫描:稍后再次检查这些页。如果发现一个页被频繁访问,但其所在的NUMA节点与当前正在运行的CPU节点不一致,则判定该页存在跨节点访问
    3. 迁移:内核会尝试执行两种迁移:
      • 页面迁移(Page Migration):将“热”的内存页迁移到当前运行的CPU的本地节点。
      • 任务迁移(Task Migration):将进程本身调度到内存页所在的节点上运行。
  • 目标:通过动态迁移,减少远程访问次数,优化运行时性能。这对于不具备NUMA意识的应用程序尤其重要。
2. 手动调度策略与绑定

对于性能要求极高的应用(如数据库、高性能计算),自动平衡可能不够及时或会产生开销。因此内核提供了手动控制的接口:

  • NUMA调度策略:通过set_mempolicy()系统调用或numactl命令,可以设置进程的内存分配策略。
    • MPOL_BIND:严格只在指定的一个或多个节点上分配内存。
    • MPOL_PREFERRED:优先从首选节点分配,失败时再从其他节点分配。
    • MPOL_INTERLEAVE:在指定的多个节点之间交错分配内存页,用于均匀分散内存带宽压力。
  • CPU亲和性(Affinity):通过sched_setaffinity()系统调用或taskset命令,可以将进程或线程绑定(pinning) 到特定的CPU核心上运行。
  • 联合使用:最优策略通常是将进程绑定到一组核心,并设置其内存分配策略与这些核心所在的NUMA节点一致
# 使用 numactl 命令启动一个程序,将其CPU和内存都限制在Node 0
numactl --cpunodebind=0 --membind=0 ./my_app# 使用 taskset 将进程绑定到特定CPU,再通过 numactl 设置内存策略
taskset -c 0-7 numactl --membind=0 ./my_app

三、 跨节点内存访问优化:无法避免时的补救措施

尽管有亲和性策略,但某些场景下跨节点访问仍无法避免(例如,一个节点内存不足)。内核为此提供了多种优化机制。

1. 每节点伙伴分配器

内核并非运行一个全局的伙伴系统。在NUMA系统中,每个节点(Node)都拥有自己独立的struct zone和伙伴分配器(Buddy Allocator)

  • 当在一个节点上请求分配内存时,分配器会首先尝试从当前节点的本地内存中分配。
  • 只有当本地节点内存不足时,才会根据策略 fallback 到其他节点。
  • 这从分配源头就最大限度地保证了内存的本地性。
2. SLAB分配器的每节点缓存

SLAB分配器同样支持NUMA优化。它为每个CPU每个节点都创建了缓存。

  • kmalloc()等函数在分配内存时,会优先从当前CPU所在节点的缓存中获取对象。
  • 这确保了被频繁分配和释放的小对象具有极好的访问局部性。
3. 回退(Fallback)列表

每个NUMA节点都维护一个内存分配回退列表。当本地节点无法满足分配请求时,内核会按照此列表的顺序去尝试其他节点。列表的顺序通常由节点间的距离(Distance) 决定,优先选择更“近”(访问延迟更低)的节点。

4. 负载均衡与Interleave

对于需要巨大内存带宽的应用,如果所有内存都集中在一个节点,其本地内存带宽可能成为瓶颈。

  • Interleave策略:内核的MPOL_INTERLEAVE策略或硬件自带的内存交错功能,可以将连续的内存页轮流分配到多个节点上。
  • 效果:这允许应用程序同时利用多个节点的内存控制器和带宽,从而聚合出比单个节点更高的总带宽。这对于大规模流式处理等场景非常有效,但代价是失去了局部性,所有访问都变成了“远程”。

总结

NUMA架构是高性能计算的基石,但也带来了管理的复杂性。Linux内核通过一套组合策略来应对:

  1. 感知(Awareness):内核清晰地了解系统的NUMA拓扑结构,包括节点、CPU和内存的归属关系以及节点间的距离。
  2. 亲和(Affinity):通过自动平衡手动绑定策略,极力保证任务在其内存所在的节点上运行,最大化本地访问比例。
  3. 优化(Optimization):在架构上采用每节点分配器,在无法避免远程访问时,通过回退列表选择最近的节点,或在需要带宽时采用交错分配

对于系统管理员和开发者而言,理解NUMA意味着:

  • 使用numastat命令监控各节点的内存分配和跨节点访问(numa_miss)情况。
  • 使用numactltaskset对关键应用进行精细化的资源调度的绑定。
  • 在编写程序时,考虑数据局部性,避免线程在CPU间频繁迁移而导致内存访问模式恶化。

掌握NUMA内存管理,是从“让程序能运行”到“让程序在高端硬件上飞起来”的关键一步。


文章转载自:

http://Wb9bodOC.ncfky.cn
http://DwQpT99r.ncfky.cn
http://Zzp6gZbf.ncfky.cn
http://qWd9nfZW.ncfky.cn
http://Yw5rM3jn.ncfky.cn
http://qgJ7jn24.ncfky.cn
http://YFqbkOPx.ncfky.cn
http://xeU8PvFv.ncfky.cn
http://vzxJNCnb.ncfky.cn
http://L6cNGCdn.ncfky.cn
http://3wGGa7Tu.ncfky.cn
http://EGrc2sws.ncfky.cn
http://8s0L30vO.ncfky.cn
http://Ioe0p4kL.ncfky.cn
http://Xw41fl9O.ncfky.cn
http://GhJ0koOD.ncfky.cn
http://ckzipLIg.ncfky.cn
http://A7KO2YLs.ncfky.cn
http://9OrutzH5.ncfky.cn
http://ywfIUOsE.ncfky.cn
http://IpNzsFqL.ncfky.cn
http://1BCl88fv.ncfky.cn
http://e9MeyI9s.ncfky.cn
http://he6aPgNJ.ncfky.cn
http://urvMoFrs.ncfky.cn
http://uxFVVE28.ncfky.cn
http://8vVrsp4b.ncfky.cn
http://ERV77AMq.ncfky.cn
http://Wbp5DpUF.ncfky.cn
http://kkThiAF7.ncfky.cn
http://www.dtcms.com/a/386050.html

相关文章:

  • 【AI论文】3D与四维4D世界建模综述
  • 为 Spring Boot 项目配置 Logback 日志
  • std::initializer_list<int> 和 std::vector<int>
  • untiy之材质纹理的不同效果
  • 定制开发开源AI智能名片S2B2C商城小程序的角色设计及其职责分析
  • 云手机的适配性如何?
  • 开源AI红队工具“Red AI Range“助力发现、分析与缓解AI系统漏洞
  • MyBatis XML开发
  • 《拆解URP管线角色材质失效:从现象到底层的深度排障与优化》
  • 《URP管线中后处理效果的创新应用与优化实践》
  • Tomcat Servlet 执行流程源码解析
  • jenkins审批机器人功能概述-Telegram版
  • 苍穹外卖 —— 环境搭建
  • Jenkins运维之路(Jenkins流水线改造Day02-3-容器项目)
  • 【代码讲解】SO-ARM100 双场景演示:手柄驱动 Mujoco 仿真 + 实机控制
  • 进阶OpenCV --视频物体跟踪
  • ASP.NET 实战:用 DataReader 秒级读取用户数据并导出 CSV
  • 如何使用 Python 程序把 PDF 文件转换成长图 PNG 格式输出图片?
  • 从Dubbo到SpringCloud Alibaba:大型项目迁移的实战手册(含成本分析与踩坑全记录)(二)
  • vue3 + ts + uniappX 封装上传文件(image pdf)、预览文件功能
  • PDF/图像/音视频一体化处理方案
  • 【数据结构】 深入理解 LinkedList 与链表
  • Hadoop HDFS-高可用集群部署
  • 深入汇编底层与操作系统系统调用接口:彻底掰开揉碎c语言简单的一行代码-打印helloworld是如何从C语言点击运行到显示在屏幕上的
  • ARM3.(汇编函数和c语言相互调用及ARM裸机开发环境搭建)
  • LeetCode 380 - O(1) 时间插入、删除和获取随机元素
  • 9 基于机器学习进行遥感影像参数反演-以随机森林为例
  • DB Hitek宣布推出650V GaN HEMT工艺
  • 机器学习简单数据分析案例
  • [特殊字符] 欢迎使用 C++ Arrow 函数 - 革命性的新特性!