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

Linux NUMA 平衡:numa_balancing 的任务与内存页迁移

简介

当前服务器硬件普遍采用 NUMA 非统一内存访问架构,多颗 CPU 各自挂载独立本地内存,节点间通过高速互联总线通信。CPU 访问自身节点内存时延低、带宽充足,跨节点远程内存访问延迟会成倍增加,频繁远程访存直接造成业务吞吐下降、响应抖动、CPU 利用率虚高。

早期工程方案依赖运维手动绑定 CPU、内存亲和性,适配繁琐且无法应对业务动态内存访问变化。Linux 内核自 3.8 版本正式引入numa_balancing自动平衡机制,无需业务代码改造,内核后台周期性检测进程内存访问热点,根据统计结果动态选择迁移任务进程或者内存物理页,让计算逻辑与数据内存尽可能收敛到同一 NUMA 节点,大幅削减远程访存开销。

该机制广泛落地于数据库集群、大数据计算、云计算虚拟化、分布式中间件、高性能科学计算等场景。对于内核研发、服务器调优工程师、虚拟化运维、后端性能开发人员而言,吃透 numa_balancing 检测逻辑、页迁移流程、调度联动规则、参数调优与异常排查,是解决 NUMA 架构性能瓶颈、定制内核调度策略、撰写技术报告与学术论文的核心能力,同时也能帮助从业者规避自动平衡带来的 CPU 抖动、迁移失败等工程问题。

一、核心概念与术语解析

1.1 NUMA 基础架构概念

SMP 对称多处理器架构下所有 CPU 共享统一内存池,访问延迟一致;NUMA 架构将整机硬件划分为多个独立节点 Node,每个 Node 包含 CPU 核心、本地内存、IO 控制器,节点间通过 QPI/UPI 总线互联。

  • 本地内存:CPU 同节点挂载内存,访问速度最快
  • 远程内存:其他节点内存,跨总线访问,延迟高、损耗大
  • NUMA 节点 ID:内核为每个硬件节点分配唯一编号,用于区分资源归属

1.2 numa_balancing 自动平衡机制

内核内置的动态优化机制,核心目标计算靠近数据,整套动作分为访问检测、热点统计、资源迁移三个阶段,两种优化路径:

  1. 页迁移:将远程热点内存页迁移至任务当前运行节点
  2. 任务迁移:将频繁访问远端内存的线程调度至内存所在节点

1.3 NUMA 缺页提示异常

机制核心触发手段,内核周期性扫描进程虚拟地址空间,将部分内存页标记为访问陷阱。进程读取写入该页面时触发NUMA hint fault异常,内核借此记录访问 CPU 节点、访问频次、访问时序,作为后续迁移判定依据。

1.4 关键内核结构体与核心函数

  1. task_struct:进程描述符,维护 numa 相关统计、优选节点、扫描状态
  2. struct page:物理页描述符,记录内存归属节点、访问计数
  3. migrate_pages:内核通用页迁移接口,完成物理页拷贝、页表刷新、TLB 同步
  4. do_numa_page:NUMA 缺页异常处理入口函数,统计访问信息并判定迁移

1.5 核心调控参数

全部位于/proc/sys/kernel/目录,管控扫描时机、迁移阈值、平衡启停

  • numa_balancing:总开关,0 关闭、1 开启自动平衡
  • numa_balancing_scan_delay_ms:进程创建后延迟首次扫描时长
  • numa_balancing_scan_period_min/max_ms:扫描间隔上下限

二、环境准备

2.1 软硬件环境规格

环境分类版本与配置要求
硬件平台多 NUMA 节点 x86_64 服务器,至少 2Node、8 核 CPU、16G 内存
操作系统Ubuntu 20.04/22.04、CentOS 7/9
内核版本Linux 5.4、5.15、6.1 主流稳定版,开启 NUMA 编译选项
编译工具gcc 9.0+、make、libncurses-dev
调试分析工具numactl、perf、ftrace、vmstat、gdb、proc 文件系统工具

2.2 内核编译配置要求

编译内核必须开启对应功能宏,否则无法使用 NUMA 自动平衡

CONFIG_NUMA=y # 启用NUMA架构支持 CONFIG_NUMA_BALANCING=y # 开启numa自动平衡核心功能 CONFIG_MIGRATION=y # 内存页迁移基础能力 CONFIG_SCHED_DEBUG=y # 调度调试与统计输出 CONFIG_FTRACE=y # 函数跟踪,观测迁移流程

2.3 环境校验与基础命令配置

  1. 查看整机 NUMA 拓扑结构,确认节点数量
numactl --hardware
  1. 查看 numa_balancing 默认开关状态
sysctl kernel.numa_balancing
  1. 一键启停自动平衡功能
# 临时开启 echo 1 > /proc/sys/kernel/numa_balancing # 临时关闭 echo 0 > /proc/sys/kernel/numa_balancing
  1. 查看全套平衡调控参数
sysctl -a | grep numa_balancing

2.4 源码文件路径定位

日常研读、调试、二次开发核心源码目录

kernel/sched/numa_balancing.c # 自动平衡主体逻辑、扫描、任务迁移 mm/migrate.c # 内存页迁移底层实现 mm/memory.c # NUMA缺页异常处理 include/linux/migrate.h # 页迁移结构体与函数声明

三、应用场景

numa_balancing 自动平衡在企业级服务器业务中不可或缺。MySQL、PostgreSQL 等数据库服务运行于双 NUMA 节点服务器,数据频繁跨节点读写,内核自动识别热点数据页并迁移至数据库进程运行节点,显著降低查询延迟、提升事务处理效率。大数据 Spark、Hadoop 计算任务分片调度分散在不同节点,自动平衡跟随计算进程迁移中间数据,减少跨节点数据拷贝耗时。云计算 KVM 虚拟机场景下,虚拟机内存散乱分布在各 NUMA 节点,平衡机制整合内存资源,优化虚拟机 IO 与运算性能。同时在工业仿真、气象算力、AI 模型推理等高负载场景,该机制动态适配任务访问特征,无需人工干预亲和性配置,规避远程访存带来的性能损耗,保障业务运行稳定性与算力输出上限。

四、实际案例与步骤、代码实操

4.1 numa_balancing 整体运行流程源码拆解

4.1.1 进程 NUMA 扫描初始化逻辑

进程创建完成后,按照延迟参数等待触发首轮内存扫描,源码节选附带注释

// kernel/sched/numa_balancing.c /* * 初始化进程NUMA扫描状态 * p:待管控进程结构体 * delay:系统配置的首次扫描延迟时间 */ void task_numa_init(struct task_struct *p, unsigned long delay) { // 重置访问统计计数 p->numa_faults = 0; // 记录下次扫描触发时间 p->numa_scan_start = jiffies + msecs_to_jiffies(delay); // 初始化优选节点,默认进程当前运行节点 p->numa_preferred_nid = task_node(p); // 标记进程纳入NUMA平衡管控队列 p->flags |= PF_NUMA_BALANCING; }

代码作用:新建进程完成基础初始化,设定扫描延时、统计变量,等待内核扫描线程遍历检测内存访问行为。

4.1.2 NUMA 缺页异常判定与统计核心函数

进程访问标记陷阱页面触发异常,内核记录访问节点与频次

// mm/memory.c static int do_numa_page(struct vm_fault *vmf) { struct page *page = vmf->page; struct task_struct *curr = current; int page_nid, curr_nid; // 获取物理页归属节点、当前运行CPU节点 page_nid = page_to_nid(page); curr_nid = task_node(curr); // 统计NUMA访问缺页次数 curr->numa_faults++; // 本地访问无需处理,直接返回 if (page_nid == curr_nid) return VM_FAULT_OK; // 远程访问,判定是否满足页迁移条件 if (numa_migrate_condition(curr, page, page_nid, curr_nid)) { // 执行错配页面迁移 migrate_misplaced_page(page, curr_nid, vmf->vma); } return VM_FAULT_OK; }

代码解析:区分本地与远程内存访问,累计访问故障次数,达到阈值后调用迁移接口,将远端页面搬迁至进程本地节点。

4.1.3 底层页面迁移核心调用函数

调用通用迁移接口,完成页面隔离、拷贝、映射刷新整套流程

// mm/migrate.c /* * 页面迁移主入口 * from:待迁移页面链表头 * get_new_page:新节点内存申请回调 * mode:迁移模式,普通NUMA平衡模式 */ int migrate_pages(struct list_head *from, new_page_t get_new_page, free_page_t put_new_page, unsigned long private, enum migrate_mode mode, int reason) { int ret = 0; struct page *page, *tmp_page; // 遍历所有待迁移物理页 list_for_each_entry_safe(page, tmp_page, from, lru) { // 锁定页面,防止迁移期间被释放修改 if (!isolate_lru_page(page)) { ret++; continue; } // 分配目标节点新物理内存 struct page *new_page = get_new_page(private); if (!new_page) { putback_lru_page(page); ret++; continue; } // 拷贝页面数据内容 copy_highpage(new_page, page); // 修改页表映射,指向新物理页 migrate_page_move_mapping(page, new_page); // 释放旧节点页面资源 put_new_page(page, private); } return ret; }

使用场景:numa_balancing 判定页面需要搬迁后,调用该函数批量迁移内存页,全程不中断业务进程运行。

4.1.4 任务节点迁移判定源码

页面迁移收益不足时,内核选择迁移进程至内存所在节点

// kernel/sched/numa_balancing.c void task_numa_migrate(struct task_struct *p) { int cur_nid = task_node(p); int best_nid = p->numa_preferred_nid; // 进程已在最优节点,无需迁移 if (cur_nid == best_nid) return; // 筛选目标节点空闲CPU核心 struct cpumask *target_cpus = numa_node_to_cpus(best_nid); // 触发调度迁移,将进程调度至目标节点CPU set_task_cpu_affinity(p, target_cpus); // 更新进程优选节点标记 p->numa_preferred_nid = cur_nid; }

4.2 编写测试程序模拟跨 NUMA 内存访问

编写 C 程序主动申请大内存,模拟业务频繁远程访存,触发自动平衡机制

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <numaif.h> #define MEM_SIZE (1024 * 1024 * 512) // 申请512MB测试内存 int main(void) { char *mem_buf; int i; // 匿名大内存申请,无固定节点绑定 mem_buf = mmap(NULL, MEM_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (mem_buf == MAP_FAILED) { perror("mmap alloc failed"); return -1; } printf("Test memory alloc success, start cross NUMA access\n"); // 循环读写内存,产生大量NUMA访问缺页 while(1) { for(i = 0; i < MEM_SIZE; i += 4096) { mem_buf[i] = 'A'; } usleep(50000); } munmap(mem_buf, MEM_SIZE); return 0; }

编译运行命令,直接复制执行

gcc numa_test.c -o numa_test -lnuma # 后台运行测试程序 ./numa_test & # 记录进程PID,后续观测统计 echo $!

程序作用:无亲和性约束下频繁读写大内存,内存散乱分布 NUMA 节点,快速触发内核扫描、缺页统计与页面迁移动作。

4.3 命令行观测 numa_balancing 运行状态

4.3.1 查看 NUMA 迁移统计数据
cat /proc/vmstat | grep numa

关键字段说明:numa_pages_migrate 成功迁移页数、numa_faults 总访问异常次数,直观判断平衡活跃度。

4.3.2 perf 抓取 NUMA 平衡内核热点函数

定位迁移、扫描相关 CPU 消耗函数

# 采样5秒内核与进程调用栈 perf record -g -p 测试程序PID sleep 5 # 解析采样报告 perf report

可观测到migrate_pagesdo_numa_page等核心函数调用频次。

4.3.4 ftrace 跟踪完整平衡调用链路

追踪扫描、异常、迁移全流程,验证源码逻辑与实际运行一致

# 挂载调试文件系统 mount -t debugfs none /sys/kernel/debug # 清空跟踪日志 echo > /sys/kernel/debug/tracing/trace # 筛选跟踪核心函数 echo migrate_pages >> /sys/kernel/debug/tracing/set_ftrace_filter echo do_numa_page >> /sys/kernel/debug/tracing/set_ftrace_filter echo task_numa_migrate >> /sys/kernel/debug/tracing/set_ftrace_filter # 开启跟踪 echo function > /sys/kernel/debug/tracing/current_tracer echo 1 > /sys/kernel/debug/tracing/tracing_on # 停止跟踪查看日志 echo 0 > /sys/kernel/debug/tracing/tracing_on cat /sys/kernel/debug/tracing/trace

4.4 手动页面迁移系统调用示例

使用 move_pages 系统调用,手动指定内存页迁移节点,对比自动平衡效果

#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <numaif.h> int main(void) { char *p; long node_id; int ret; unsigned long pages; p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); pages = (unsigned long)p; node_id = 1; // 将内存页手动迁移至node1节点 ret = move_pages(0, 1, &pages, &node_id, NULL, MPOL_MF_MOVE); if(ret < 0) { perror("move pages failed"); return -1; } printf("Manual page migrate to node 1 success\n"); munmap(p, 4096); return 0; }

五、常见问题与解答

Q1 开启 numa_balancing 后业务出现短暂 CPU 抖动、延迟突增是什么原因?

解答:页面迁移会触发内存拷贝、页表修改、TLB 刷新,占用 CPU 资源。短时间大批量页面搬迁就会产生抖动,高延迟业务可适当拉长扫描间隔,降低迁移触发频率,或业务低峰期启用平衡机制。

Q2 自动平衡频繁迁移任务进程,反而造成负载不均衡如何处理?

解答:内核优先页迁移,访问跨度极大时才会迁移进程。出现频繁进程切换,可手动对核心业务做 CPU 亲和绑定,限制进程调度节点范围,规避无效任务迁移。

Q3 查看 vmstat 发现 numa_pages_migrate 数值为 0,平衡机制未生效?

解答:一是内核未开启 CONFIG_NUMA_BALANCING 编译选项;二是进程内存全部本地分配,无远程访问行为;三是平衡总开关被关闭。依次核对内核配置、sysctl 参数、内存访问模式即可排查。

Q4 页面迁移失败率偏高,报错页面被占用无法隔离怎么办?

解答:处于 IO 读写、锁定状态、共享引用过多的页面无法迁移。减少业务内存频繁锁操作,降低页面竞争引用,同时内核会跳过不可迁移页面,不影响整体业务运行。

Q5 虚拟化虚拟机内部是否建议开启 numa_balancing?

解答:宿主机层面完成 NUMA 平衡即可,虚拟机内部关闭自动平衡,双层平衡策略冲突会造成内存反复无效迁移,损耗性能。

六、实践建议与最佳实践

  1. 开关精细化管控:数据库、低延迟交易业务默认开启平衡;时延敏感、固定算力调度的业务关闭自动平衡,采用手动 numactl 绑定亲和性。

  2. 扫描参数调优技巧:业务波动大、访问模式多变场景,调小扫描间隔快速适配热点;稳态运行业务增大延迟与间隔,减少内核扫描带来的资源开销。

  3. 故障排查固定流程:性能下降先查看 vmstat NUMA 统计,再用 perf 定位迁移函数开销,结合 ftrace 追踪调用链路,区分是访问模式问题还是内核平衡策略异常。

  4. 资源部署优化原则:核心业务进程尽量独占 NUMA 节点资源,减少多业务混合挤占节点内存,从源头降低跨节点访存概率,减轻平衡机制负载。

  5. 内核定制开发规范:二次修改 numa_balancing 逻辑时,保留页面与任务双迁移兜底策略,增加迁移开销判定阈值,避免无收益无效迁移占用系统资源。

  6. 测试环境验证准则:新内核、新业务上线前,搭建多 NUMA 节点测试机复现访问场景,观测平衡效果与抖动情况,再部署至生产服务器。

七、总结与应用延伸

本文系统性拆解 Linux numa_balancing 自动平衡机制,从基础概念、环境搭建、拓扑查看、内核源码、测试程序、命令观测到问题排查、工程优化,完整还原任务扫描、缺页统计、页面迁移、进程调度迁移整套运行逻辑。该机制核心价值是以自动化方式解决 NUMA 架构远程内存访问性能缺陷,无需业务改造就能适配动态内存访问特征,平衡资源分布。

在实际工程落地中,numa_balancing 是服务器性能调优、虚拟化资源调度、大数据算力优化的核心抓手;在内核学习与学术研究层面,吃透机制能够深入理解内存管理、调度域、软硬件拓扑协同设计思想,可支撑内核论文撰写、调度策略定制、服务器架构方案设计。

建议读者基于文中源码与测试代码,在双节点 NUMA 服务器反复实操,修改扫描参数观察迁移频次变化,对比开关平衡前后业务时延、CPU 利用率差异,真正掌握自动平衡的优势与边界约束,将理论知识运用到数据库运维、云计算部署、内核开发真实项目当中。

http://www.cnnetsun.cn/news/2562604.html

相关文章:

  • 鸿蒙electron框架PC适配:ExifCleaner 适配鸿蒙全过程:一次从“能启动”到“能处理文件”的完整复盘
  • 微信小程序项目实战:从npm安装Vant Weapp到解决样式冲突的完整避坑指南
  • 越权漏洞实战图谱:水平、垂直、目录与SQL跨库越权详解
  • 【行业首曝】Midjourney V6模糊渲染链路逆向分析:GPU显存分配偏差导致的边缘失焦真相
  • 解密前端文件下载:实战FileSaver.js跨浏览器解决方案
  • 为ClaudeCode配置Taotoken作为可靠后备API服务商
  • 零信任架构下的DeepSeek安全测试辅助调用规范,NIST SP 800-218合规实操手册
  • 在 Python 项目中快速接入多模型 API 并管理调用成本
  • PptxGenJS:用JavaScript自动化生成专业PPT的终极指南
  • 035、模拟与数字分区布局策略
  • 终极LaTeX转Word公式神器:3分钟让数学公式在Word中完美呈现
  • Rust 属性语法
  • 数字员工赋能熊猫智汇,提升AI销冠系统整体效能与企业运营能力
  • SuperCom:终极串口调试解决方案与高效开发指南
  • 创业团队如何借助Taotoken统一管理多个AI项目API成本
  • 独立指纹传感器开关设计:从模块选型到继电器驱动全解析
  • 【时间之外】私有化部署AI的3个优点和3个缺点
  • GEO生成引擎优化2026技术全景:从底层原理到落地框架,这篇讲透了
  • Linux概述与系统部署
  • 在Node.js服务中集成Taotoken实现稳定高效的大模型API调用
  • 利用Taotoken实现AI应用的高可用与故障路由策略
  • 对象初始化过程深度解析
  • Vue2-Verify:5种验证码类型,轻松为Vue项目添加安全验证
  • 简历评分避坑:这些“加分项”其实是扣分雷区,别再踩了!
  • 别只盯着效率:在iPad上用UTM虚拟机跑起Win10后,我发现的3个真实使用场景
  • Icarus Verilog:颠覆性开源硬件验证工具,从零构建你的数字王国
  • DeepSeek推理速度提升300%?揭秘LLM量化压缩与KV缓存优化实战路径
  • AI 到底是怎么访问网页的?从爬虫、Browser Agent 到 Computer Use
  • 单机部署DeepSeek-R1-32B,实测吞吐达114 tokens/sec(附完整Prometheus+Grafana监控看板配置)
  • AI教材生成大揭秘:低查重工具实测,快速完成教材编写任务!