LWN: NUMA对各种内存类型的分配策略!

关注了就能看到更多这么棒的文章哦~

NUMA policy and memory types

By Jonathan Corbet
July 16, 2021
DeepL assisted translation
https://lwn.net/Articles/862707/

非统一内存访问(NUMA, Non-uniform memory access)系统架构中,会将内存都跟系统的各个 "node (节点)"关联起来。CPU 也是从属于某个 node 节点的。如果 CPU 在访问的是属于同一个 node 的内存的话,访问速度比起访问其他 node 的内存会更快。这里的性能差异对于在 NUMA 系统上运行的程序有比较大的影响,因此内核为用户空间提供了许多方法来优化应用程序的行为。不过,NUMA 这个概念现在也正在进行扩展,人们也就需要新方法来控制内存的分配过程。因此引出了 multi-pefeenc memory policy 这组 patch 来满足这一需求。

Memory policies

从来没有一个放之四海而皆准的分配策略可以做到为所有场景下都提供最佳性能。如果一个应用程序可以完全在一个 NUMA 节点内运行的话,那么最好的策略就是分配的所有内存都要来自这个节点,这样一来,所有的访问都是本地访问(因此速度很快)。较大的应用程序则可能希望分配的内存都来自几个特定节点。除此之外其他的应用程序的最好策略可能就是在整个系统中分配内存,这样一来所有的 CPU 的性能表现就会基本一致,系统整体带宽也会最优。一般来说,内核不可以判定适合某个特定进程的最佳策略是什么。

因此,需要由 user space 来帮助 kernel 选择相应的内存分配策略,这里有两个系统调用可以提供帮助。set_mempolicy() 函数可以供调用线程(calling thread)用来设置默认的内存策略,而 mbind() 则为调用进程的地址空间中的某一个特定部分设置策略。这两个系统调用有许多可选参数。例如可以使用 MPOL_PREFERRED 来要求内核在可能的情况下优先在一个 "preffered" node 上分配内存。进程也可以使用 MPOL_BIND 来提供一组节点列表,来指定内存分配都要来自这些特定节点。MPOL_INTERLEAVE 则要求内核在内存分配时每个 page 都分散到指定的节点上。还有一些其他类似策略。

这些选项通常来说足以满足那些需要性能调优的应用程序了。至少,它们曾经是足够了。但是现在内存技术正在发生一些变化。内核对 NUMA 的支持当初设计的时候世界还是这么一个情况:连接到任何一个系统上的内存都是同样的规格,影响性能的唯一关键就是内存连接的是哪个节点。当时人们唯一感兴趣的参数就某块内存区域对 CPU 来说是不是算是本地访问。

The plot thickens

然而,现在越来越多的系统都拥有多种类型的内存了。目前最常见的例子是安装了持久性内存(persistent memory)的系统。虽然这种内存可以用来作为长期存储设备,但它也可以作为一种速度比较慢的普通 RAM 来使用。持久性内存的优点是相对便宜,安装了大量持久性内存的话,可能就可以补足它在许多场景中较低性能的缺点了。同时,供应商也在研发一些比普通 DRAM 更快的高性能内存,但这类内存还是太贵了,不能把系统中的全部内存都完全替换成这种高性能的内存。

这就给内核(和用户空间)提出了一个以前不需要考虑的问题:应该使用哪种类型的内存来满足分配请求?到目前为止采用的解决方案是将这些特殊的内存都统一用一些特殊的、不包含 CPU 的 NUMA 节点中管理起来。如果某个应用程序知道自己需要大量的慢速内存的话,就可以设置其内存策略来从相应的节点中分配内存,这样就能拿到慢速内存了。

不过,以这种方式来使用现有的 NUMA 框架的话有一个小问题:它跟人们想解决的问题不是非常匹配。一个愿意使用慢速内存的应用程序就像是一个经济舱的乘客,如果在分配内存(登机)时给它进行一下升级(升舱),它肯定会喜出望外。因此该应用程序虽然可能会建议从慢速内存节点来进行分配,但如果慢速内存中空间不够了的话,应该回到正常内存来进行分配。

MPOL_BIND 的定义中不允许这种行为,因为它的判定更加严格。如果申请的策略是 MPOL_BIND,而在指定的节点上没有可用的内存的话,就会出现一些人们通常不愿看到的结果。比如 out-of-memory killer 进程会开始杀死一些进程来回收内存,此外也可能想要分配内存的这个进程会意外收到 SIGSEGV 信号。进程愿意使用较慢的内存,并不代表它们就希望在这部分内存不可用的时候看到自己进程崩溃,所以用户认为 MPOL_BIND 有点太过于死板来,他们的看法也是很有道理的。

某种意义上来说,MPOL_PREFERRED 似乎是这里比较适合的选项。它表达了一种偏好,如果首选节点没有可用的内存,就可以不用这个节点。问题是,由于一些只有该接口的设计者知道的原因,MPOL_PREFERRED 只允许指定一个 preferred 节点。如果所需的内存分布在多个节点上的话(这种情况很可能会发生),那么这个接口就无法让一个应用程序利用到所有的内存了。

Multi-preference policies

Multi-preference memory policy patch set 来自于 Feng Tang、Dave Hansen 和 Ben Widawsky 的工作,它试图通过增加另一个叫做 MPOL_PREFERRED_MANY 的选项来解决这个问题。它的行为与 MPOL_PREFERRED 类似,只是它允许指定多个节点。使用这个选项的程序可以要求从一组提供了所需类型的内存的节点中进行分配,但是如果这些节点中的资源不足了的话,内核可以从其他地方进行分配。这个 patch 本身是比较简单的,尽管它确实需要一些开发工作来修改所有需要使用这个新选项的地方的代码。

这项工作解决了眼前的问题,但它事实上回避了一个相关问题:NUMA 的抽象是不是用来解决这种选择不同类型内存的需求的最合适的方案呢?有人赞成,因为:这种方式现在就可以正常用起来,不需要一个全新 API 来管理内存分配,而且通常也跟底层硬件实际体系架构是相匹配的。反对者则认为,它事实上把两个无关的问题(内存类型和位置)混在了一起,并迫使用户空间的代码来解决这些问题。这令人感觉有点不太合适。

这已经不是第一次提出这种问题了,但人们仍然不太希望增加新的 API。历史经验表明,只要 NUMA API 可以用来解决选择内存类型的问题的话,就不会有很大的动力去开发其他方案来解决这个问题。因为潜在的好处可能比不上需要付出的大量额外成本。所以 MPOL_PREFERRED_MANY 可能会是最终的解决方案。patch set 似乎已经准备好了,这个新增选项可能很快就会出现在 5.15 的 mainline kernel 中。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值