資料庫伺服器的NUMA最佳化問題

qing_yun發表於2023-12-21

幾年前我曾經寫過一篇關於資料庫與NUMA的文章,主要是當時有DBA問我是不是在LINUX上關閉了NUMA,就不會有NUMA引發的效能問題了。當時我用UMA和NUMA架構的兩張圖來說明其實不完全如此。

早期的SMP架構的伺服器CPU和記憶體配置都不多,因此CPU透過匯流排訪問記憶體就可以了,隨著硬體的發展,記憶體從MB級別已經達到了TB級別,而CPU也從單顆CPU1-2核變成了數十核,甚至上百核的龐然大物。因此傳統的UMA中的匯流排就成為瓶頸了。因此NUMA架構開始興起。

NUMA架構中,CPU透過高效能的記憶體通道與記憶體相連,而不再透過系統匯流排。每個CPU上都有記憶體控制單元和數個記憶體通道,CPU透過記憶體管理單元來透過QPI匯流排訪問本地記憶體。這種架構的好處是CPU訪問記憶體的效能得到了保證,壞處是當系統中存在多顆CPU的時候,記憶體就分為了本地記憶體與遠端記憶體兩種。比如CPU0訪問Memory0-3的時候,可以直接訪問,效能最佳,而如果要訪問Memory4-7的時候,就需要透過匯流排,由CPU1代理訪問,其效率就不如直接訪問本地記憶體了。

可以看出上面的這個例子中一共有2個NUMA節點,每個NUMA節點管理了32GB的記憶體。node distances是距離單位,這個值並不是一個具體指,數值越小說明記憶體離CPU的距離越近,訪問效能越好。對於INTEL CPU來說,本地記憶體與遠端記憶體的距離大約是2.1倍,訪問效能差不多也是接近2倍的差距。在一個ARM伺服器中,這個距離差距可能是5倍,甚至更高。因此不管ARM伺服器的CPU效能有多強,在跑一些資料庫之類的負載的時候,似乎會不如看上去跑分還沒有自己強的INTEL CPU了。實際上資料庫負載與記憶體、儲存系統的訪問效能關係很大,不僅僅和CPU自身的效能指標相關。

另外要注意的一點是遠端記憶體與本地記憶體的訪問效能差異是一個物理限制,而不是邏輯限制,因此這個問題並不會因為在作業系統啟動時關閉NUMA而得到改善的。

討論完上面的預備知識,下面就要談談NUMA架構會如何影響資料庫了。首先一個問題就是有時候明明看到實體記憶體還有不少空閒,但是SWAP已經使用了不少了。這時候我們可以透過numactl -H來看看是不是多個NUMA節點上的記憶體分配不均衡,有的NUMA節點上還有很多空閒記憶體,而有些NUMA節點上的記憶體已經耗盡了。zone_reclaim_mode、overcommit_memory等作業系統引數的設定也會影響多個NUMA節點上記憶體的分配策略。

為了避免這種 情況出現,很多資料庫廠商的服務人員都會建議關閉SWAP,從而避免在實體記憶體還有足夠空閒的時候出現不必要的換頁,從而影響資料庫的效能。達夢、Oceanbase等資料庫廠商都在自己的官方建議裡提出過此類建議。不過我是不太建議不分青紅皂白關閉SWAP的,因為關閉SWAP雖然可以避免因為不必要的換頁引發的效能問題,但是可能會因為真正記憶體不足使導致更為嚴重的問題,比如因為實體記憶體確實不夠用了而導致資料庫例項直接被作業系統oom killer殺掉,導致資料庫當機。針對達夢、Oceanbase這樣的單程式多執行緒架構的資料庫,一旦出現實體記憶體不足,資料庫服務被清理的機率肯定是最大的。

要想避免這類問題,資料庫例項啟動後,應該調整oom_score引數的值,比如在LINUX 3.1以上的環境中,直接設定為-1000,這樣oom killer在找需要釋放記憶體的程式的時候,會避開資料庫服務程式。

上述的解決方案能解決關閉SWAP後的大部分記憶體不足引發的資料庫例項當機問題,不過並不是能解決所有問題的。如果記憶體缺得厲害了,系統可能會因為實體記憶體週轉不足而引發十分嚴重的效能問題,甚至導致OS僵死,重啟等。因此是否關閉SWAP是一個需要綜合考慮的問題。其實如果不關閉SWAP,在作業系統啟動時關閉NUMA就可以避免此類問題,關閉NUMA後,作業系統將不對記憶體分割槽,記憶體分配是全域性性的。因此在大多數場景中,我是建議不關閉SWAP,而是在作業系統啟動時關閉NUMA。

有朋友看到這裡會說,老白,你上來直接就說這種配置就行了,有必要洋洋灑灑寫一千多字才丟擲這個小技巧嗎?實際上問題還沒有徹底解決。關閉NUMA只是解決了記憶體分割槽導致的不必要的SWAP問題。本地記憶體與遠端記憶體的訪問效率問題還是沒有解決,這個問題實際上是解決不了的。要想解決,必須在資料庫核心上去解決。目前已經有一些資料庫在針對NUMA進行最佳化了,包括Oracle在內。很多國產資料庫也把基於NUMA最佳化當成一個自己的亮點。

資料庫基於NUMA最佳化實際上目的也是儘可能使用本地記憶體這點思路。程式或者執行緒啟動後繫結到某個CPU組中,並且儘可能優先使用本CPU組的本地記憶體,從而提高資料庫的整體效能。對於INTEL CPU的伺服器來說,遠端記憶體效能問題還不是很嚴重,不過如果我們要使用某些信創CPU,那麼這個差異可能對效能的影響就很大了。因此說資料庫針對NUMA做核心最佳化還是很必要的。只不過目前的絕大多數國產資料庫在針對NUMA記憶體的最佳化上都只是做了些皮毛,對跑BENCHMARK可能比較有效,但是針對實際的應用場景來說,效果甚微。這是因為資料庫記憶體中,最需要提升效能的是共享記憶體的訪問效能,而這部分記憶體針對NUMA架構的最佳化技術難度還是很高的。

來自 “ 白鱔的洞穴 ”, 原文作者:白鱔;原文連結:https://mp.weixin.qq.com/s/BF4GD61ZcNPYRCQZQ7ru5Q,如有侵權,請聯絡管理員刪除。

相關文章