为 Hadoop YARN Container 开启 NUMA 感知

本文简述了Hadoop YARN Container NUMA 感知相关配置。主要参考资料来自维基百科YARN-5764

什么是NUMA?

非均匀内存访问 (NUMA) 是一种用于多处理的计算机内存设计,其中内存访问时间取决于相对于处理器的内存位置。 在 NUMA 下,处理器可以比非本地内存(另一个处理器本地的内存或处理器之间共享的内存)更快地访问自己的本地内存。NUMA 的好处仅限于特定的工作负载,尤其是在数据通常与某些任务或用户密切相关的服务器上。

现代 CPU 的运行速度比它们使用的主内存快得多,因此,CPU 越来越多地发现自己出现“数据饥饿”的情形,并且在数据从内存到达期间必须等待。限制内存访问次数是从现代计算机中获得高性能的关键。对于商用处理器,这意味着安装越来越多的高速缓存,并使用越来越复杂的算法来避免缓存未命中。但是,操作系统和在其上运行的应用程序规模的急剧增加通常使这些缓存处理改进不堪重负。

在这种情况下,没有 NUMA 的多处理器系统使问题变得更加严重。现在一个系统可以同时饿死几个处理器,因为一次只有一个处理器可以访问计算机的内存。NUMA 尝试通过为每个处理器提供单独的内存来解决这个问题,从而避免在多个处理器尝试寻址同一内存时对性能造成影响。对于涉及传播数据的问题(常见于服务器和类似应用程序),NUMA 可以将单个共享内存的性能提高,倍数约为处理器数量(或单独的内存库)。解决这个问题的另一种方法是多通道内存架构,其中内存通道数量的线性增加也会将内存访问并发性线性增加。

当然,并非所有数据最终都局限于单个任务,这意味着多个处理器可能需要相同的数据。 为了处理这些情况,NUMA 系统包括额外的硬件或软件来在内存库之间移动数据。 此操作会减慢连接到这些组的处理器的速度,因此 NUMA 带来的整体速度增加在很大程度上取决于正在运行的任务的性质。

除了硬件支持,将虚拟内存分页添加到集群架构可以允许完全在软件中实现 NUMA。 然而,基于软件的 NUMA 的节点间延迟仍然比基于硬件的 NUMA 大几个数量级。

Yarn Containers 可以利用这种 NUMA 设计,通过绑定到特定的 NUMA 节点来获得更好的性能,并且所有后续内存分配都将由同一节点提供服务,从而减少远程内存访问。

设计方案

NUMAResourcesManager 是节点管理器中添加的服务类,用于处理 NUMA 节点分配/调度。 它将在节点管理器中启用 NUMA 感知时启动。 作为其初始化的一部分,它从系统或基于属性的配置中读取 NUMA 拓扑(节点及其内存和 CPU)。每当容器执行程序通过 NUMAResourcesManager API 请求 NUMA 节点信息时,NUMAResourcesManager 会以轮询方式从可用资源中为请求的内存和 CPU 分配节点。 在某些情况下,如果单个节点中没有可用的请求资源,则 NUMAResourcesManager 可能会分配多个节点。

ContainerExecutor 使用 API 从 NUMAResourcesManager 获取 NUMA 节点信息(用于请求内存和 CPU),然后它在使用 NUMA API 启动时将容器绑定到那些用于内存和 CPU 的节点(numactl --membind=<node> --cpunodebind=<node>)。

准备工作

在硬件支持的基础上,可以在机器里安装numactl,随后调用numactl --hardware查看节点信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ numactl --hardware
available: 8 nodes (0-7)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 31018 MB
node 0 free: 4369 MB
node 1 cpus: 8 9 10 11 12 13 14 15
node 1 size: 32730 MB
node 1 free: 3057 MB
node 2 cpus: 16 17 18 19 20 21 22 23
node 2 size: 32730 MB
node 2 free: 3663 MB
node 3 cpus: 24 25 26 27 28 29 30 31
node 3 size: 32730 MB
node 3 free: 2174 MB
node 4 cpus: 32 33 34 35 36 37 38 39
node 4 size: 32730 MB
node 4 free: 4095 MB
node 5 cpus: 40 41 42 43 44 45 46 47
node 5 size: 32730 MB
node 5 free: 3283 MB
node 6 cpus: 48 49 50 51 52 53 54 55
node 6 size: 32730 MB
node 6 free: 2612 MB
node 7 cpus: 56 57 58 59 60 61 62 63
node 7 size: 32698 MB
node 7 free: 3321 MB
node distances:
node 0 1 2 3 4 5 6 7
0: 10 20 40 30 20 30 50 40
1: 20 10 30 20 30 20 40 30
2: 40 30 10 20 50 40 20 30
3: 30 20 20 10 40 30 30 20
4: 20 30 50 40 10 20 40 30
5: 30 20 40 30 20 10 30 20
6: 50 40 20 30 40 30 10 20
7: 40 30 30 20 30 20 20 10

相关配置

开启 NUMA 节点感知

yarn-site.xml 里加入:

1
2
3
4
<property>
<name>yarn.nodemanager.numa-awareness.enabled</name>
<value>true</value>
</property>

默认情况下这个功能是关闭的。

读取 NUMA 拓扑信息

yarn-site.xml 里加入:

1
2
3
4
<property>
<name>yarn.nodemanager.numa-awareness.enabled</name>
<value>true</value>
</property>

此属性决定是从系统还是从配置中读取 NUMA 拓扑。 如果此属性值为 true,则将在 UNIX 系统中使用 numactl --hardware 命令从系统中读取拓扑,在 Windows 中使用类似的方式。 如果此属性为 false,则将使用以下配置读取拓扑。 此配置的默认值为 false,这意味着 NodeManager 将从以下配置中读取 NUMA 拓扑。

手动配置 NUMA 节点信息

这里共有三个信息需要配置:

  • yarn.nodemanager.numa-awareness.node-ids: 以逗号分隔的形式提供 NUMA 节点 ID,例如 0,1,2
  • yarn.nodemanager.numa-awareness.<NODE_ID>.memory: 对于以上的每个节点 ID,为每个 NUMA 节点配置内存(以 MB 为单位)
  • yarn.nodemanager.numa-awareness.<NODE_ID>.cpus: 对于以上的每个节点 ID,为每个 NUMA 节点配置 CPU

额外配置

  • yarn.nodemanager.numa-awareness.numactl.cmd: numactl 的位置,默认为 /usr/bin/numactl

性能测试

YARN-5764提供了性能测试报告,使用了 Hive on MapReduce 执行引擎,对 100G 和 1T 的工作负载进行了测试。测试结果显示,对于100G 的工作负载有 6.18% 的提升,对 1T 的工作负载有 15.14% 的提升。测试详情可以参考YARN-5764里面的附件。