Linux 核心 101:NUMA架構

liaochangjiang發表於2019-04-17

本文參考了以下文章、視訊:

一句話

NUMA 指的是針對某個 CPU,記憶體訪問的距離和時間是不一樣的。是為了解決多 CPU 系統下共享 BUS 帶來的效能問題。(這句話可能不太嚴謹,不是為了解決,而是事實上解決了。)

NUMA 架構圖

從最簡單的開始,一個 CPU(注意:這裡指的是物理 CPU,不是核。需要注意的一點是NUMA 是針對多物理 CPU 而言的,而不是多核。),通過 bus 和 RAM 相連。

Linux 核心 101:NUMA架構

接下來多CPU 出現了(再說一次,不是多核單CPU!),如果還是像之前那樣將所有的CPU 通過一個 BUS 和 RAM 相連,BUS 會成為效能的殺手。而且,加的 CPU 越多,效能損耗會越高。

Linux 核心 101:NUMA架構

這時候 NUMA 架構就展露身手了:通過把 CPU 和臨近的 RAM 當做一個 node,CPU 會優先訪問距離近的 RAM。同時,CPU 直接有一個快速通道連線,所以 每個CPU 還是訪問到所有的 RAM 位置(只是速度會有差異)。

Linux 核心 101:NUMA架構

實際中,一個不一定單獨佔有一個 RAM,可以有下面這些很多種組合:

Linux 核心 101:NUMA架構

Linux 核心 101:NUMA架構

淺看 Linux 中的NUMA架構

以下操作在阿里云云伺服器 Ubuntu18.04環境下執行

首先通過dmesg | grep -i numa檢視一下系統是不是支援numa:可見當前系統不支援 :)

Linux 核心 101:NUMA架構

然後使用一個工具:numactl,可以通過 apt install numactl進行安裝。然後執行:

numactl --hardware
複製程式碼

Linux 核心 101:NUMA架構

還有一個實用工具:lstopo,通過 apt install lstopo

lstopo --of png > server.png
複製程式碼

Linux 核心 101:NUMA架構

從圖中可以看到,有一個node 節點。為什麼我的系統不支援 numa,Linux 還是把所有的 CPU 和所有的 RAM 組合到一起成為一個 node 呢?這不是閒的沒事幹嗎?

關於這一點,《Understanding the Linux Kernel》一書裡面這麼說:

Linux 核心 101:NUMA架構

這主要是出於程式碼可擴充套件性的考慮,這樣一套程式碼就可以在不支援 numa 和支援 numa 的環境下執行了。

如果是支援 numa 架構的伺服器,看到的圖會是這樣的:

Linux 核心 101:NUMA架構

NUMA 對Linux 會產生什麼影響?

系統 boot 的時候,硬體會把 numa 資訊傳送給 os,如果系統支援 numa,會發生以下幾件事:

  • 獲取 numa 配置資訊
  • 將 processors(不是 cores) 分成很多 nodes,一般是一個 processor 一個 node。
  • 將 processor 附近的 memory 分配給它。
  • 計算node 間通訊的cost(距離)。

如果你只是把 CPU 和記憶體當作是黑盒子,簡單地期待它 work 的話,可能會發生意想不到的事情。

  • 每個程式、執行緒都會繼承一個 numa policy,定義了可以使用那些CPU(甚至是那些 core),哪些記憶體可以使用,以及 policy 的強制程度,即是優先還是強制性只允許。
  • 每個 thread 被分配到了一個”優先” 的 node 上面執行,thread 可以在其他地方執行(如果 policy 允許的話),但是 os 會嘗試讓他在優先地 node 上面去執行。
  • 記憶體分配:預設記憶體從同一個 node 裡面進行分配。
  • 在一個 node 上面分配地記憶體不會被移動到其他node。

上面兩段翻譯自: blog.jcole.us/2010/09/28/… ,如有不清晰的地方,請移步原文。

看一個MySQL 的例項

優質好文,有能力的同學最好還是直接看原文: blog.jcole.us/2010/09/28/… 我這裡簡單翻譯一下。

文中提到了一個問題:在一個有64G 記憶體、2個 4核 CPU 的 Linux 伺服器中執行 MySQL 服務,MySQL 配置了48G 的 innodb buffer pool。然後發現,儘管系統還有很多空餘的內容,很多記憶體被 swap 出去了。

這帶來了極大的效能問題,因為query 的時候如果需要的內容被 swap 出去了。。就需要再 load 回來。這也是困惱了MySQL 社群很長時間的問題。

前面說到 Linux 有一個 numa policy,這個是可以人為控制的。

  • —localalloc ,使用當前 node,預設。
  • --preferred=node,優先實用指定的 node,實在不行用其他的 nod 也可以。
  • --membind=nodes,總是使用人為指定一個或多個 nodes。
  • --interleaved=all,採用round-robin演算法輪流使用不同的 node。

從 Linux os 的角度來看,MySQL 資料庫就是一個程式,會優先讓他在某一個 node 中執行。如果只是使用少部分記憶體,這沒什麼問題,但是當你要佔用系統大多數記憶體的時候,問題就來了:

由於 os 會試圖讓你在某個『優先』的node裡面執行,就會產生記憶體分配不均勻的情況:

Linux 核心 101:NUMA架構

Node0 已經快被佔滿了,Node1還剩下很多。由於 node0和 node1是獨立的,儘管 node1裡面有空餘記憶體,node0裡面的記憶體還是會被 swap 出去。這就是前面提到的問題的根源。

那麼怎麼解決呢?

numactl --interleave all command
複製程式碼

用前面提到的--interleave all numa policy,將這段新增到mysqld_save 語句前面。過後,記憶體分配就是均勻的了,記憶體足夠的情況下,就不會出現異常的 swap 現象了。

Linux 核心 101:NUMA架構

當然這只是一個最簡單粗暴的解決方案,還有其他更好的,原文有提及,但是不是本文的重點,所以就不深入探討了。

總結一下

摩爾定律正在失效,當 CPU 的效能總會有極限的那一天,多 CPU 才是未來。作為一個有理想的搬磚工人,至少還是應該多瞭解一下多 CPU 系統架構。作為一個系統軟體開發者,更應該熟悉多 CPU 架構,讓自己開發的應用充分利用硬體福利。

Linux 核心 101:NUMA架構

廣告時間,歡迎大家關注我的微信公眾號。同時本文同步於 github: github.com/liaochangji…

Linux 核心 101:NUMA架構

相關文章