本文参考了以下这篇论文:
A Case for NUMA-aware Contention Management on Multicore Systems 直接点击链接就可以下载
回顾一下上篇文章
上一篇文章 简单地介绍了一下多 CPU 下的 NUMA 架构。NUMA 架构中将内存划分为多个不同的区域,将 CPU 和临近的内存组成一个 node 节点,OS 调度的时候会优先使用临近的内存,从而解决了之前 UMA 架构下 BUS 带来的性能问题(因为多个 CPU 会对这一条总线产生竞争)。同时也讲到了在 MySQL 在 NUMA 架构下遇到的“swap insanity”问题,也就是当 MySQL 占用的内存超过 (100 / node 总数) % 时,由于『优先使用临近内存』这个调度模式的存在,造成了内存分配不均,导致系统整体内存充足的情况下,依然出现大量『不正常』的的 swap 现象。如下图所示:
本文内容概括
本文将从『资源竞争管理』的角度切入,将会看到 UMA 时代的竞争管理算法将不再适用于 NUMA,并给出具体的原因分析和解决方案。看完之后相信你一定会对 NUMA 有更加深刻的理解,并对多 CPU 时代的编程有个感性的认识。
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%。至于原因,下文将会给出。
为什么不适用?
在 NUMA 架构下,CAS 会感知有哪些相互竞争的 threads,然后把其中一个移到不同的 domain 中。这会导致一种情况:thread 的内存没有分配在该 thread 运行的那个 node 里面,比如说上图中,一个 thread 本来运行在 c1 上,之后由于竞争被移到 c5 上了,但是它的 memory 还在 M1。我们把这种由于移动 thread,导致 thread 和它的内存分家的行为称作『NUMA-agnostic migrations』(agnostic 中文意思是不可知,自已意会一下~)。
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 的性能。
interconnect connection。(这点影响会很严重)
remote access。
总结一下
NUMA-agnostic migrations 无法提高 甚至还会降低 NUMA 竞争管理的性能,按照对性能的影响程度排序有:
没能够解决对 memory controller 的竞争关系(memory 还在原来那个地方)。
引起了额外的 interconnect connection。
引起了额外的 remote access。
原论文中还提到了作者自己研究出的一种解决方案,有兴趣的同学可以去啃一下原文。
相信你看完了,应该对 NUAM 架构有了一个比较感性的认识了吧。觉得写的不错(看在 gakki 的情面上)不点个赞鼓励一下?
广告时间,欢迎大家关注我的微信公众号。同时本文同步于 github:https://github.com/liaochangjiang/TechDaily