Linux 内核101:NUMA下的竞争管理

本文参考了如下这篇论文:node

回顾一下上篇文章

上一篇文章 简单地介绍了一下多 CPU 下的 NUMA 架构。NUMA 架构中将内存划分为多个不一样的区域,将CPU 和临近的内存组成一个 node 节点,OS 调度的时候会优先使用临近的内存,从而解决了以前 UMA 架构下 BUS 带来的性能问题(由于多个 CPU 会对这一条总线产生竞争)。同时也讲到了在MySQL在 NUMA 架构下遇到的 “swap insanity”问题,也就是当MySQL 占用的内存超过 (100 / node 总数) % 时,因为『优先使用临近内存』这个调度模式的存在,形成了内存分配不均,致使系统总体内存充足的状况下,依然出现大量『不正常』的的 swap 现象。以下图所示:git

本文内容归纳

本文将从『资源竞争管理』的角度切入,将会看到UMA 时代的竞争管理算法将再也不适用于 NUMA,并给出具体的缘由分析和解决方案。看完以后相信你必定会对 NUMA有更加深入的理解,并对多CPU 时代的编程有个感性的认识。github

UMA 竞争管理算法对 NUMA 不适用

有共享资源的地方,就会有竞争。有竞争,就会有性能损失。算法

一直以来,多核系统的共享资源竞争都是一个大问题。内核之间互相竞争共享资源,好比 last-level cache(LLC)、系统请求队列和内存管理器等。目前比较流行的解决方案叫作 contention-aware scheduler(竞争感知调度程序,下面简称为 CAS),也就是说它可以区分在互相竞争共享资源的 threads,而后把他们分开到不一样的 domain。有数据显示,这种调度方法能够提升最坏状况下80%、平均10%的性能。编程

这种算法在 UMA 中是有效的。可是须要考虑到的是, NUMA 相比 UMA 有一点很大的不一样,那就是 UMA 只有一个 memory node,配备一个 memory controller;而 NUMA中 每一个 node 里面都有一个 memory node,各自配备了一个 memory controller,以下图所示:16个核被分为了4个 node,每一个 node 有一个独立的 memory(固然每一个核均可以访问任意位置的内存)。微信

那么这种调度方式到底起不起做用呢?若是只是简单的想一下的话,也许会以为为何不行呢?若是同一个 node 里面的 threads 竞争特别激烈,那我就把其中一个移到另外一个 node 上,虽说这会带来必定的延迟,可是竞争就解决了啊。架构

而后,事情没那么简单,一切真理都来自于实践,实践发现,在 NUMA 上面实施这种调度算法的时候,非但没能很好地解决竞争,反而性能降低了30%。至于缘由,下文将会给出。dom

为何不适用?

在 NUMA 架构下,CAS 会感知有哪些相互竞争的 threads,而后把其中一个移到不一样的 domain 中。这会致使一种状况:thread的内存没有分配在该thread 运行的那个 node 里面,好比说上图中,一个 thread 原本运行在 c1上,以后因为竞争被移到 c5上了,可是它的 memory 还在 M1。咱们把这种因为移动 thread,致使 thread 和它的内存分家的行为称做『NUMA-agnostic migrations』(agnostic 中文意思是不可知,自已意会一下~)。post

NUMA-agnostic migrations致使了一些问题,比较明显一点的是thread 获取内存的延迟提升了,不过这还不是关键。更重要的是,NUMA-agnostic migrations没法缓解一些关键资源(memory controller)的竞争问题,甚至还引发对更多资源(interconnect connection)的竞争。性能

下面这张图很重要,请仔细看:

解释一下:T 和 C 分别表示两个程序(thread)

  • 图0:两个程序相安无事,没有竞争关系。
  • 图1:CT 的内存在一个 node,对 memory controller(MC) 产生了竞争关系。(应该还有访问延迟,图中可能忘记标注了)
  • 图2: 两个程序都须要试用进行CPU 之间的快速通道,产生了interconnect connection(IC)竞争。同时还有访问远程 memory 带来的访问延迟(RL)。
  • 图3:memory controller (MC)竞争,加上远程访问延时(RL)。
  • 图4:TC 位于一个 CPU 里面,对 last-level cache(CA) 产生竞争关系。
  • 图5:CA + RL
  • 图6:CA + MC
  • 图7:最坏的状况,CA + MC + IC + MC

实验发现,图3的性能降低了110%。缘由在于 threads 仍是在相互竞争 memory controller。NUMA-agnostic migrations在迁移 thread 的时候,颇有可能最后会致使这种状况出现。

假如如今有两个threads,A 和 B,A 运行在图一中的 c1上,B 运行在 c2上,他们之间存在竞争关系(竞争last-level cache)。如今有一个 contention-aware 调度器检测到了 A 和 B 的竞争关系,因而把 B 移动到 c5上去了,如今A 和 B 再也不竞争 last-level cache 了。事实上在 UMA 系统中这的确是起做用了(虽然对于 memory controller 的竞争仍是存在的)。

可是对于 NUMA,A 和 B 的 memory 还在一个地方,对于 最关键资源memory controller 的竞争没有获得解决。并且还引来了两个问题,这两个问题会严重影响 B 的性能。

  1. interconnect connection。(这点影响会很严重)
  2. remote access。

总结一下

NUMA-agnostic migrations没法提升 甚至还会下降NUMA竞争管理的性能,按照对性能的影响程度排序有:

  1. 没可以解决对 memory controller 的竞争关系(memory 还在原来那个地方)。
  2. 引发了额外的 interconnect connection。
  3. 引发了额外的 remote access。

原论文中还提到了做者本身研究出的一种解决方案,有兴趣的同窗能够去啃一下原文。

相信你看完了,应该对 NUAM 架构有了一个比较感性的认识了吧。以为写的不错(看在gakki 的情面上)不点个赞鼓励一下?

广告时间,欢迎你们关注个人微信公众号。同时本文同步于 github: github.com/liaochangji…