NUMA架构的CPU
本文從NUMA的介紹引出常見的NUMA使用中的陷阱,繼而討論對(duì)于NUMA系統(tǒng)的優(yōu)化方法和一些值得關(guān)注的方向。
文章歡迎轉(zhuǎn)載,但轉(zhuǎn)載時(shí)請(qǐng)保留本段文字,并置于文章的頂部
作者:盧鈞軼(cenalulu)
本文原文地址:http://cenalulu.github.io/linux/numa/
NUMA簡(jiǎn)介
這部分將簡(jiǎn)要介紹下NUMA架構(gòu)的成因和具體原理,已經(jīng)了解的讀者可以直接跳到第二節(jié)。
為什么要有NUMA
在NUMA架構(gòu)出現(xiàn)前,CPU歡快的朝著頻率越來越高的方向發(fā)展。受到物理極限的挑戰(zhàn),又轉(zhuǎn)為核數(shù)越來越多的方向發(fā)展。如果每個(gè)core的工作性質(zhì)都是share-nothing(類似于map-reduce的node節(jié)點(diǎn)的作業(yè)屬性),那么也許就不會(huì)有NUMA。由于所有CPU Core都是通過共享一個(gè)北橋來讀取內(nèi)存,隨著核數(shù)如何的發(fā)展,北橋在響應(yīng)時(shí)間上的性能瓶頸越來越明顯。于是,聰明的硬件設(shè)計(jì)師們,先到了把內(nèi)存控制器(原本北橋中讀取內(nèi)存的部分)也做個(gè)拆分,平分到了每個(gè)die上。于是NUMA就出現(xiàn)了!
NUMA是什么
NUMA中,雖然內(nèi)存直接attach在CPU上,但是由于內(nèi)存被平均分配在了各個(gè)die上。只有當(dāng)CPU訪問自身直接attach內(nèi)存對(duì)應(yīng)的物理地址時(shí),才會(huì)有較短的響應(yīng)時(shí)間(后稱Local Access)。而如果需要訪問其他CPU attach的內(nèi)存的數(shù)據(jù)時(shí),就需要通過inter-connect通道訪問,響應(yīng)時(shí)間就相比之前變慢了(后稱Remote Access)。所以NUMA(Non-Uniform Memory Access)就此得名。
我們需要為NUMA做什么
假設(shè)你是Linux教父Linus,對(duì)于NUMA架構(gòu)你會(huì)做哪些優(yōu)化?下面這點(diǎn)是顯而易見的:
既然CPU只有在Local-Access時(shí)響應(yīng)時(shí)間才能有保障,那么我們就盡量把該CPU所要的數(shù)據(jù)集中在他local的內(nèi)存中就OK啦~
沒錯(cuò),事實(shí)上Linux識(shí)別到NUMA架構(gòu)后,默認(rèn)的內(nèi)存分配方案就是:優(yōu)先嘗試在請(qǐng)求線程當(dāng)前所處的CPU的Local內(nèi)存上分配空間。如果local內(nèi)存不足,優(yōu)先淘汰local內(nèi)存中無用的Page(Inactive,Unmapped)。
那么,問題來了。。。
NUMA的“七宗罪”
幾乎所有的運(yùn)維都會(huì)多多少少被NUMA坑害過,讓我們看看究竟有多少種在NUMA上栽的方式:
- MySQL – The MySQL “swap insanity” problem and the effects of the NUMA architecture
- PostgreSQL – PostgreSQL, NUMA and zone reclaim mode on linux
- Oracle – Non-Uniform Memory Access (NUMA) architecture with Oracle database by examples
- Java – Optimizing Linux Memory Management for Low-latency / High-throughput Databases
究其原因幾乎都和:“因?yàn)镃PU親和策略導(dǎo)致的內(nèi)存分配不平均”及“NUMA Zone Claim內(nèi)存回收”有關(guān),而和數(shù)據(jù)庫種類并沒有直接聯(lián)系。所以下文我們就拿MySQL為例,來看看重內(nèi)存操作應(yīng)用在NUMA架構(gòu)下到底會(huì)出現(xiàn)什么問題。
MySQL在NUMA架構(gòu)上會(huì)出現(xiàn)的問題
幾乎所有NUMA + MySQL關(guān)鍵字的搜索結(jié)果都會(huì)指向:Jeremy Cole大神的兩篇文章
- The MySQL “swap insanity” problem and the effects of the NUMA architecture
- A brief update on NUMA and MySQL
大神解釋的非常詳盡,有興趣的讀者可以直接看原文。博主這里做一個(gè)簡(jiǎn)單的總結(jié):
- CPU規(guī)模因摩爾定律指數(shù)級(jí)發(fā)展,而總線發(fā)展緩慢,導(dǎo)致多核CPU通過一條總線共享內(nèi)存成為瓶頸
- 于是NUMA出現(xiàn)了,CPU平均劃分為若干個(gè)Chip(不多于4個(gè)),每個(gè)Chip有自己的內(nèi)存控制器及內(nèi)存插槽
- CPU訪問自己Chip上所插的內(nèi)存時(shí)速度快,而訪問其他CPU所關(guān)聯(lián)的內(nèi)存(下文稱Remote Access)的速度相較慢三倍左右
- 于是Linux內(nèi)核默認(rèn)使用CPU親和的內(nèi)存分配策略,使內(nèi)存頁盡可能的和調(diào)用線程處在同一個(gè)Core/Chip中
- 由于內(nèi)存頁沒有動(dòng)態(tài)調(diào)整策略,使得大部分內(nèi)存頁都集中在CPU 0上
- 又因?yàn)镽eclaim默認(rèn)策略優(yōu)先淘汰/Swap本Chip上的內(nèi)存,使得大量有用內(nèi)存被換出
- 當(dāng)被換出頁被訪問時(shí)問題就以數(shù)據(jù)庫響應(yīng)時(shí)間飆高甚至阻塞的形式出現(xiàn)了
解決方案
Jeremy Cole大神推薦的三個(gè)方案如下,如果想詳細(xì)了解可以閱讀?原文
- numactl --interleave=all
- 在MySQL進(jìn)程啟動(dòng)前,使用sysctl -q -w vm.drop_caches=3清空文件緩存所占用的空間
- Innodb在啟動(dòng)時(shí),就完成整個(gè)Innodb_buffer_pool_size的內(nèi)存分配
這三個(gè)方案也被業(yè)界普遍認(rèn)可可行,同時(shí)在?Twitter 的5.5patch?和?Percona 5.5 Improved NUMA Support?中作為功能被支持。
不過這種三合一的解決方案只是減少了NUMA內(nèi)存分配不均,導(dǎo)致的MySQL SWAP問題出現(xiàn)的可能性。如果當(dāng)系統(tǒng)上其他進(jìn)程,或者M(jìn)ySQL本身需要大量?jī)?nèi)存時(shí),Innodb Buffer Pool的那些Page同樣還是會(huì)被Swap到存儲(chǔ)上。于是又在這基礎(chǔ)上出現(xiàn)了另外幾個(gè)進(jìn)階方案
- 配置vm.zone_reclaim_mode = 0使得內(nèi)存不足時(shí)去remote memory分配優(yōu)先于swap out local page
- echo -15 > /proc/<pid_of_mysqld>/oom_adj調(diào)低MySQL進(jìn)程被OOM_killer強(qiáng)制Kill的可能
- memlock
- 對(duì)MySQL使用Huge Page(黑魔法,巧用了Huge Page不會(huì)被swap的特性)
重新審視問題
如果本文寫到這里就這么結(jié)束了,那和搜索引擎結(jié)果中大量的Step-by-Step科普帖沒什么差別。雖然我們用了各種參數(shù)調(diào)整減少了問題發(fā)生概率,那么真的就徹底解決了這個(gè)問題么?問題根源究竟是什么?讓我們回過頭來重新審視下這個(gè)問題:
NUMA Interleave真的好么?
為什么Interleave的策略就解決了問題?
借用兩張?Carrefour性能測(cè)試?的結(jié)果圖,可以看到幾乎所有情況下Interleave模式下的程序性能都要比默認(rèn)的親和模式要高,有時(shí)甚至能高達(dá)30%。究其根本原因是Linux服務(wù)器的大多數(shù)workload分布都是隨機(jī)的:即每個(gè)線程在處理各個(gè)外部請(qǐng)求對(duì)應(yīng)的邏輯時(shí),所需要訪問的內(nèi)存是在物理上隨機(jī)分布的。而Interleave模式就恰恰是針對(duì)這種特性將內(nèi)存page隨機(jī)打散到各個(gè)CPU Core上,使得每個(gè)CPU的負(fù)載和Remote Access的出現(xiàn)頻率都均勻分布。相較NUMA默認(rèn)的內(nèi)存分配模式,死板的把內(nèi)存都優(yōu)先分配在線程所在Core上的做法,顯然普遍適用性要強(qiáng)很多。
也就是說,像MySQL這種外部請(qǐng)求隨機(jī)性強(qiáng),各個(gè)線程訪問內(nèi)存在地址上平均分布的這種應(yīng)用,Interleave的內(nèi)存分配模式相較默認(rèn)模式可以帶來一定程度的性能提升。
此外?各種?論文?中也都通過實(shí)驗(yàn)證實(shí),真正造成程序在NUMA系統(tǒng)上性能瓶頸的并不是Remote Acess帶來的響應(yīng)時(shí)間損耗,而是內(nèi)存的不合理分布導(dǎo)致Remote Access將inter-connect這個(gè)小水管塞滿所造成的結(jié)果。而Interleave恰好,把這種不合理分布情況下的Remote Access請(qǐng)求平均分布在了各個(gè)小水管中。所以這也是Interleave效果奇佳的一個(gè)原因。
那是不是簡(jiǎn)簡(jiǎn)單單的配置個(gè)Interleave就已經(jīng)把NUMA的特性和性能發(fā)揮到了極致呢?
答案是否定的,目前Linux的內(nèi)存分配機(jī)制在NUMA架構(gòu)的CPU上還有一定的改進(jìn)空間。例如:Dynamic Memory Loaction, Page Replication。
Dynamic Memory Relocation
我們來想一下這個(gè)情況:MySQL的線程分為兩種,用戶線程(SQL執(zhí)行線程)和內(nèi)部線程(內(nèi)部功能,如:flush,io,master等)。對(duì)于用戶線程來說隨機(jī)性相當(dāng)?shù)膹?qiáng),但對(duì)于內(nèi)部線程來說他們的行為以及所要訪問的內(nèi)存區(qū)域其實(shí)是相對(duì)固定且可以預(yù)測(cè)的。如果能對(duì)于這把這部分內(nèi)存集中到這些內(nèi)存線程所在的core上的時(shí)候,就能減少大量Remote Access,潛在的提升例如Page Flush,Purge等功能的吞吐量,甚至可以提高M(jìn)ySQL Crash后Recovery的速度(由于recovery是單線程)。
那是否能在Interleave模式下,把那些明顯應(yīng)該聚集在一個(gè)CPU上的內(nèi)存集中在一起呢?
很可惜,Dynamic Memory Relocation這種技術(shù)目前只停留在理論和實(shí)驗(yàn)階段。我們來看下難點(diǎn):要做到按照線程的行為動(dòng)態(tài)的調(diào)整page在memory的分布,就勢(shì)必需要做線程和內(nèi)存的實(shí)時(shí)監(jiān)控(profile)。對(duì)于Memory Access這種非常異常頻繁的底層操作來說增加profile入口的性能損耗是極大的。在?關(guān)于CPU Cache程序應(yīng)該知道的那些事的評(píng)論中我也提到過,這個(gè)道理和為什么Linux沒有全局監(jiān)控CPU L1/L2 Cache命中率工具的原因是一樣的。當(dāng)然優(yōu)化不會(huì)就此停步。上文提到的Carrefour算法和Linux社區(qū)的Auto NUMA patch都是積極的嘗試。什么時(shí)候內(nèi)存profile出現(xiàn)硬件級(jí)別,類似于CPU中?PMU?的功能時(shí),動(dòng)態(tài)內(nèi)存規(guī)劃就會(huì)展現(xiàn)很大的價(jià)值,甚至?xí)鳛長(zhǎng)inux Kernel的一個(gè)內(nèi)部功能來實(shí)現(xiàn)。到那時(shí)我們?cè)倩剡^頭來審視這個(gè)方案的實(shí)際價(jià)值。
Page Replication
再來看一下這些情況:一些動(dòng)態(tài)加載的庫,把他們放在任何一個(gè)線程所在的CPU都會(huì)導(dǎo)致其他CPU上線程的執(zhí)行效率下降。而這些共享數(shù)據(jù)往往讀寫比非常高,如果能把這些數(shù)據(jù)的副本在每個(gè)Memory Zone內(nèi)都放置一份,理論上會(huì)帶來較大的性能提升,同時(shí)也減少在inter-connect上出現(xiàn)的瓶頸。實(shí)時(shí)上,仍然是上文提到的Carrefour也做了這樣的嘗試。由于缺乏硬件級(jí)別(如MESI協(xié)議的硬件支持)和操作系統(tǒng)原生級(jí)別的支持,Page Replication在數(shù)據(jù)一致性上維護(hù)的成本顯得比他帶來的提升更多。因此這種嘗試也僅僅停留在理論階段。當(dāng)然,如果能得到底層的大力支持,相信這個(gè)方案還是有極大的實(shí)際價(jià)值的。
究竟是哪里出了問題
NUMA的問題?
NUMA本身沒有錯(cuò),是CPU發(fā)展的一種必然趨勢(shì)。但是NUMA的出現(xiàn)使得操作系統(tǒng)不得不關(guān)注內(nèi)存訪問速度不平均的問題。
Linux Kernel內(nèi)存分配策略的問題?
分配策略的初衷是好的,為了內(nèi)存更接近需要他的線程,但是沒有考慮到數(shù)據(jù)庫這種大規(guī)模內(nèi)存使用的應(yīng)用場(chǎng)景。同時(shí)缺乏動(dòng)態(tài)調(diào)整的功能,使得這種悲劇在內(nèi)存分配的那一刻就被買下了伏筆。
數(shù)據(jù)庫設(shè)計(jì)者不懂NUMA?
數(shù)據(jù)庫設(shè)計(jì)者也許從一開始就不會(huì)意識(shí)到NUMA的流行,或者甚至說提供一個(gè)透明穩(wěn)定的內(nèi)存訪問是操作系統(tǒng)最基本的職責(zé)。那么在現(xiàn)狀改變非常困難的情況下(下文會(huì)提到為什么困難)是不是作為內(nèi)存使用者有義務(wù)更好的去理解使用NUMA?
總結(jié)
其實(shí)無論是NUMA還是Linux Kernel,亦或是程序開發(fā)他們都沒有錯(cuò),只是還做得不夠極致。如果NUMA在硬件級(jí)別可以提供更多低成本的profile接口;如果Linux Kernel可以使用更科學(xué)的動(dòng)態(tài)調(diào)整策略;如果程序開發(fā)人員更懂NUMA,那么我們完全可以更好的發(fā)揮NUMA的性能,使得無限橫向擴(kuò)展CPU核數(shù)不再是一個(gè)夢(mèng)想。
- Percona NUMA aware Configuration
- Numa system performance issues – more than just swapping to consider
- MySQL Server and NUMA architectures
- Checking /proc/pid/numa_maps can be dangerous for mysql client connections
- on swapping and kernels
- Optimizing Linux Memory Management for Low-latency / High-throughput Databases
- Memory System Performance in a NUMA Multicore Multiprocessor
- A Case for NUMA-aware Contention Management on Multicore Systems
總結(jié)
以上是生活随笔為你收集整理的NUMA架构的CPU的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国大数据专业公司
- 下一篇: Zookeeper与paxos算法