1. NUMA 简介 

传统的 SMP(Symmetric Multi-Processor)系统中,所有处理器都共享系统 总线,因此当处理器的数目增大时,系统总线的竞争冲突加大,系统总线将成为 瓶颈,可扩展能力受到极大限制。 

由于 SMP 在扩展能力上的限制,人们开始探究如何进行有效地扩展从而构建 大型系统的技术,NUMA(Non-Uniform Memory Access)就是这种努力下的结果之 一。利用 NUMA 技术,可以把几十个CPU(甚至上百个 CPU)组合在一个服务器内。 

NUMA 服务器的基本特征是具有多个 CPU 节点,每个 CPU 节点由多个 CPU 组 成,并且具有独立的本地内存、I/O 槽口等。由于其节点之间可以通过互联模块 进行连接和信息交互,因此每个 CPU 可以访问整个系统的内存。显然,访问本地 内存的速度将远远高于访问远地内存(系统内其它节点的内存)的速度,这也是非 一致存储访问 NUMA 的由来。 

使用 NUMA 的模式如果能尽量保证本 node 内的 CPU 只访问本 node 内的内存 块,那这样的效率就是最高的。NUMA 策略(NUMA Policy)即是指在多个节点上合 理的进行内存分配的机制。对于不同软件设计要求,策略的目标可能会不同:有 一些设计可能强调低延迟访问,另一些则可能更加看重内存的访问带宽。 

NUMA 的 CPU 分配策略有 cpunodebind、physcpubind。cpunodebind 规定进 程运行在某几个 node 之上,而 physcpubind 可以更加精细地规定运行在哪些核 上。 

NUMA 的内存分配策略有 localalloc、preferred、membind、interleave。 localalloc 规定进程从当前 node 上请求分配内存;而 preferred 比较宽松地指 定了一个推荐的 node 来获取内存,如果被推荐的 node 上没有足够内存,进程可 以尝试别的 node。membind 可以指定若干个 node,进程只能从这些指定的 node 上请求分配内存。interleave 规定进程从指定的若干个 node 上以 RR 算法交织 地请求分配内存。 

每个进程(或线程)都会从父进程继承 NUMA 策略,并分配有一个优先 node。 如果 NUMA 策略允许的话,进程可以调用其他 node 上的资源。 

基于 2.6 之后的 Linux 内核版本的各主要 linux 发行版,如 Redhat,SUSE 等均包括了面向用户空间的 numautils 工具包,提供对 NUMA 系统内存策略的监 控功能,并开放面向用户空间程序的 API 接口。该接口习惯上称为 NUMA API。 

NUMA API 主要任务是管理 NUMA 的内存策略。NUMA 策略通过几个子系统的协 同工作来实现。内核管理进程的内存分配机制以及特殊的内存映射。NUMA API 通过新引入的 3 个内核系统调用来实现这一点。在用户空间中,NUMA API 通过 libnuma 库提供了统一的接口供用户空间程序使用。相对于系统调用,libnuma 接口更加清晰易用。同时 NUMA API 还提供了命令行工具 numactl 和 numastat 来帮助系统管理员实现进程级别的策略管理。 

在 Linux 上 NUMA API 支持四种内存分配策略:


l 缺省(default):总是在本地节点分配(分配在当前线程运行的节点上);

l 绑定(bind):分配到指定节点上;


l 交织(interleave):在所有节点或者指定的节点上交织分配;


l 优先(preferred):在指定节点上分配,失败则在其他节点上分配。

绑定和优先的区别是,在指定节点上分配失败时(如无足够内存),绑定策 略会报告分配失败,而优先策略会尝试在其他节点上进行分配。强制使用绑定有 可能会导致前期的内存短缺,并引起大量换页。在 libnuma 库中,优先和绑定是 组合在一起的。通过对线程调用 uma_set_strict 函数,可以在两种策略间切换。 缺省的策略是更加普适的优先策略。 

策略可以基于进程或内存区域设定。进程策略对整个进程内的内存分配都有 效,而内存区域策略作用于指定的内存区域,其优先级比进程策略要高。 



2. 可能出现的问题及其原因 

在 NUMA 架构的系统上运行 SequoiaDB 可能会导致一些问题,包括性能下降、 较高的 CPU 负载等。在访问大数据量的集合时,可能会导致操作操作系统卡顿甚 至卡死。 

出现问题的原因在于 Linux 内核默认使用 default 的内存分配策略:优先尝 试在请求线程当前所处的 CPU 的 Local 内存上分配空间;如果 local 内存不足, 优先淘汰 local 内存中无用的 Page。由于内存页没有动态调整策略,使得大部 分内存页都集中在某一个 CPU 上,又因为优先淘汰本 CPU 上的内存,使得大量有 用内存被换出。当被换出页被访问时问题就以数据库响应时间飙高甚至阻塞的形 式出现了。甚至在禁用 swap 分区的情况下直接导致内核崩溃。 



3. 解决办法


在 NUMA 架构的系统上运行 SequoiaDB 时,需要关闭 NUMA,并将内核参数 vm.zone_reclaim_mode 设为 0。 关闭 NUMA 的方法包括:

1) 在BIOS中设置关闭NUMA;


2) 在Linux内核启动参数上设置numa=off;


3) 用numactl命令将内存分配策略修改为interleave。