应用级 NUMA 策略
应用可以通过系统调用自行设置 NUMA 内存策略:set_mempolicy 作用于调用线程之后的分配,mbind 作用于指定的内存区间。常用策略有 MPOL_DEFAULT(沿用默认)、MPOL_BIND(只从指定节点分配)、MPOL_PREFERRED(优先指定节点但允许兜底)、MPOL_INTERLEAVE(在多个节点间交错,提升带宽利用率)。策略按线程生效且可被继承,线程池应用要留意策略是否被带到其他工作线程。
基本信息
| 接口 | set_mempolicy(2) 与 mbind(2) |
|---|---|
| 作用域 | set_mempolicy 为线程级,mbind 为内存区间级 |
| 主要策略 | DEFAULT、BIND、PREFERRED、INTERLEAVE |
| 观测 | numastat -p <pid> 看进程的节点分布 |
| 命令行封装 | numactl 提供等价的启动方式 |
典型使用场景
- 内存带宽受限的服务用交错分配摊开访问
- 确定性要求高的服务需要绑定到单一节点
- 排查线程池中部分线程跨节点访存的问题
- 与 numactl 命令行方案做对比选择
- 大页与 NUMA 策略组合使用时评估效果
C 调用片段
C 调用片段
unsigned long mask = 1UL << 0; // 位图表示节点集合
set_mempolicy(MPOL_BIND, &mask, 64); // 之后的内存分配绑定 0 号节点
unsigned long mask2 = (1UL << 0) | (1UL << 1);
mbind(addr, len, MPOL_INTERLEAVE, &mask2, 64, 0); // 该区间在两个节点间交错
numactl -H | head -20 # 先确认节点与核的拓扑
numastat -p <pid> # 观察进程实际落在哪些节点
numactl --hardware | grep -E 'node|size'策略对照
| 策略 | 含义 | 适用场景 |
|---|---|---|
| MPOL_DEFAULT | 沿用线程或系统默认 | 没有特殊访存要求 |
| MPOL_BIND | 只从指定节点分配 | 要求确定性、避免跨节点访问 |
| MPOL_PREFERRED | 优先指定节点,允许兜底 | 希望就近但不愿意分配失败 |
| MPOL_INTERLEAVE | 在多个节点间交错分配 | 带宽密集型负载,避免单节点争抢 |
策略按线程生效并可被继承:线程池创建新线程时应显式重设,否则可能继承到不该有的节点绑定。
BIND 策略下节点内存不足会直接导致分配失败,而不是回退到其他节点;应与备用节点、监控与容量规划一起考虑。
与命令行方案的取舍
- numactl 适合在启动时一次性设定,服务化部署时复用简单
- 应用内调用适合需要按运行阶段或线程粒度调整策略的场景
- 两者混用时以最后设置的为准,排查时按时间顺序核对生效值