自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為什么 NUMA 會(huì)影響程序的延遲

存儲(chǔ) 存儲(chǔ)軟件
為什么這么設(shè)計(jì)(Why’s THE Design)是一系列關(guān)于計(jì)算機(jī)領(lǐng)域中程序設(shè)計(jì)決策的文章,我們?cè)谶@個(gè)系列的每一篇文章中都會(huì)提出一個(gè)具體的問題并從不同的角度討論這種設(shè)計(jì)的優(yōu)缺點(diǎn)、對(duì)具體實(shí)現(xiàn)造成的影響。如果你有想要了解的問題,可以在文章下面留言。

[[348624]]

為什么這么設(shè)計(jì)(Why’s THE Design)是一系列關(guān)于計(jì)算機(jī)領(lǐng)域中程序設(shè)計(jì)決策的文章,我們?cè)谶@個(gè)系列的每一篇文章中都會(huì)提出一個(gè)具體的問題并從不同的角度討論這種設(shè)計(jì)的優(yōu)缺點(diǎn)、對(duì)具體實(shí)現(xiàn)造成的影響。如果你有想要了解的問題,可以在文章下面留言。

非一致性內(nèi)存訪問(Non-Uniform Memory Access、NUMA)是一種計(jì)算機(jī)內(nèi)存的設(shè)計(jì)方式[^1],與 NUMA 相對(duì)的還有一致性內(nèi)存訪問(Uniform Memory Access、UMA),也被稱作對(duì)稱多處理器架構(gòu)(Symmetric Multi-Processor、SMP),早期的計(jì)算機(jī)都會(huì)使用 SMP,然而現(xiàn)代的多數(shù)計(jì)算機(jī)都會(huì)采用 NUMA 架構(gòu)管理 CPU 和內(nèi)存資源。

uma-and-numa

 

圖 1 - UMA 和 NUMA

作為應(yīng)用程序的開發(fā)者,因?yàn)椴僮飨到y(tǒng)為我們屏蔽了很多硬件層面的實(shí)現(xiàn)細(xì)節(jié),所以不太需要直接接觸硬件,不過因?yàn)?NUMA 會(huì)影響應(yīng)用程序,所以想要寫出高性能、低延遲的服務(wù),NUMA 是我們必須要了解并熟悉的,本文將從以下兩個(gè)方面介紹它的影響:

  • NUMA 引入了本地內(nèi)存和遠(yuǎn)程內(nèi)存,CPU 訪問本地內(nèi)存的延遲會(huì)小于訪問遠(yuǎn)程內(nèi)存;
  • NUMA 的內(nèi)存分配與內(nèi)存回收策略結(jié)合時(shí)會(huì)可能會(huì)導(dǎo)致 Linux 的頻繁交換分區(qū)(Swap)進(jìn)而影響系統(tǒng)的穩(wěn)定性;

本地內(nèi)存

如果主機(jī)使用 NUMA 這種架構(gòu)設(shè)計(jì),那么 CPU 訪問本地內(nèi)存的延遲會(huì)小于訪問遠(yuǎn)程內(nèi)存,這種現(xiàn)象并不是 CPU 設(shè)計(jì)者刻意制造的,而是物理層面的限制。不過 NUMA 這種設(shè)計(jì)并不是與計(jì)算機(jī)一同誕生的,我們?cè)诶^續(xù)分析 NUMA 對(duì)程序的影響之前先來分析一下 CPU 架構(gòu)的演進(jìn)過程。

在計(jì)算機(jī)誕生的最初幾十年,處理器基本都是單核的,根據(jù)摩爾定律,隨著技術(shù)的進(jìn)步,處理器的性能每隔兩年就會(huì)翻一倍[^2],這一定律在上個(gè)世紀(jì)基本都是生效的,然而在過去十幾年,單個(gè)處理器中晶體管數(shù)目的增加速度逐漸放緩,很多廠商開始推出了雙核以及多核的計(jì)算機(jī)。

moores-law

 

圖 2 - 摩爾定律

單核或者多核計(jì)算機(jī)上的 CPU 最早會(huì)通過前端總線(Front-side bus)、北橋(Northbridge)和內(nèi)存總線(Memory bus)訪問內(nèi)存槽中的內(nèi)存,所有的 CPU 會(huì)通過相同的總線訪問相同的內(nèi)存以及 I/O 設(shè)備,計(jì)算機(jī)中的所有資源都是共享的,這種架構(gòu)被稱作對(duì)稱多處理器架構(gòu)(Symmetric Multi-Processor、SMP),也被稱為一致存儲(chǔ)器訪問結(jié)構(gòu)(Uniform Memory Access、UMA)。

single-and-multi-core

 

圖 3 - 單核和多核處理器

然而隨著計(jì)算機(jī)中 CPU 數(shù)量的增加,多個(gè) CPU 都需要通過總線和北橋訪問內(nèi)存,當(dāng)同一個(gè)主機(jī)中包含幾十個(gè) CPU 時(shí),總線和北橋兩個(gè)模塊成為了系統(tǒng)的瓶頸,為了解決這一問題,CPU 架構(gòu)的設(shè)計(jì)者使用如下所示的多個(gè) CPU 模塊解決了這個(gè)問題:

numa-local-remote-access

 

圖 4 - 雙節(jié)點(diǎn) NUMA 架構(gòu)

如上圖所示,該主機(jī)中包含 2 個(gè) NUMA 節(jié)點(diǎn),每個(gè) NUMA 節(jié)點(diǎn)都包含物理 CPU 和內(nèi)存,從圖中我們可以看出 CPU 1 訪問本地內(nèi)存和遠(yuǎn)程內(nèi)存會(huì)經(jīng)過不同的通道,這是訪問內(nèi)存時(shí)間不同的根本原因。

操作系統(tǒng)作為管理計(jì)算機(jī)硬件、軟件資源并為應(yīng)用程序提供通用服務(wù)的軟件,它本身就會(huì)與底層的硬件打交道,Linux 操作系統(tǒng)就會(huì)為我們提供硬件相關(guān)的 NUMA 信息,你可以直接通過 numactl 命令查看機(jī)器上的 NUMA 節(jié)點(diǎn)[^3]:

  1. $ numactl -H 
  2. available: 2 nodes (0-1) 
  3. node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 24 25 26 27 28 29 30 31 32 33 34 35 
  4. node 0 size: 63539 MB 
  5. node 0 free: 18566 MB 
  6. node 1 cpus: 12 13 14 15 16 17 18 19 20 21 22 23 36 37 38 39 40 41 42 43 44 45 46 47 
  7. node 1 size: 64485 MB 
  8. node 1 free: 20716 MB 
  9. node distances: 
  10. node   0   1 
  11.   0:  10  21 
  12.   1:  21  10 

從上述輸出結(jié)果我們可以看出,該機(jī)器上包含兩個(gè) NUMA 節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)上都包含 24 個(gè) CPU 以及 64GB 的內(nèi)存,最后的節(jié)點(diǎn)距離(node distances)告訴我們兩個(gè) NUMA 節(jié)點(diǎn)訪問內(nèi)存的開銷,其中 NUMA 節(jié)點(diǎn) 0 和 NUMA 節(jié)點(diǎn) 1 互相訪問對(duì)方內(nèi)存的延遲是各自節(jié)點(diǎn)訪問本地內(nèi)存的 2.1 倍(21 / 10 = 2.1),所以如果 NUMA 節(jié)點(diǎn) 0 上的進(jìn)程如果在節(jié)點(diǎn) 1 上分配內(nèi)存,會(huì)增加進(jìn)程的延遲。

正是因?yàn)?NUMA 節(jié)點(diǎn)訪問不同內(nèi)存的開銷不同,所以操作系統(tǒng)會(huì)為應(yīng)用程序提供接口控制 CPU 和內(nèi)存的分配策略,在 Linux 系統(tǒng)中,我們可以使用 numactl 命令控制進(jìn)程使用的 CPU 和內(nèi)存。

numactl 提供了 cpunodebind 和 physcpubind 兩種策略為進(jìn)程分配 CPU,這兩種策略分別提供了不同粒度的綁定方法:

  • cpunodebind — 將進(jìn)程綁定到某幾個(gè) NUMA 節(jié)點(diǎn)上;
  • physcpubind — 將進(jìn)程綁定到某幾個(gè)物理 CPU 上;

除了這兩種 CPU 分配策略之外,numactl 還提供四種不同的內(nèi)存分配策略,分別是:localalloc、preferred、membind 和 interleave:

  • localalloc — 總是在當(dāng)前節(jié)點(diǎn)上分配內(nèi)存;
  • preferred — 傾向于在特定節(jié)點(diǎn)上分配內(nèi)存,當(dāng)指定節(jié)點(diǎn)的內(nèi)存不足時(shí),操作系統(tǒng)會(huì)在其他節(jié)點(diǎn)上分配;
  • membind — 只能在傳入的幾個(gè)節(jié)點(diǎn)上分配內(nèi)存,當(dāng)指定節(jié)點(diǎn)的內(nèi)存不足時(shí),內(nèi)存的分配就會(huì)失敗;
  • interleave — 內(nèi)存會(huì)在傳入的節(jié)點(diǎn)上依次分配(Round Robin),當(dāng)指定節(jié)點(diǎn)的內(nèi)存不足時(shí),操作系統(tǒng)會(huì)在其他節(jié)點(diǎn)上分配;

上述的兩種 CPU 分配策略和四種內(nèi)存分配策略是我們與 NUMA 打交道時(shí)經(jīng)常需要接觸的,當(dāng)進(jìn)程的性能受到 NUMA 的影響時(shí),我們可能需要通過 numactl 命令調(diào)整 CPU 或者內(nèi)存的分配策略。

交換分區(qū)

NUMA 架構(gòu)雖然能夠解決總線上的性能瓶頸并可以讓我們?cè)谕粋€(gè)主機(jī)上運(yùn)行更多的 CPU,但是如果不了解 NUMA 的工作原理或者使用錯(cuò)誤的策略會(huì)帶來一些問題,Jeremy Cole 的文章 The MySQL “swap insanity” problem and the effects of the NUMA architecture 就曾經(jīng)分析過 NUMA 架構(gòu)下 MySQL 可能出現(xiàn)的問題 — 頻繁發(fā)生的交換分區(qū)影響服務(wù)延遲[^4],我們?cè)谶@里簡(jiǎn)單介紹一下該問題背后的原因:

uneven-memory-node

 

圖 5 - 分配不均勻的內(nèi)存

因?yàn)?MySQL 等數(shù)據(jù)庫(kù)的運(yùn)行會(huì)占用大量的內(nèi)存,在默認(rèn)情況進(jìn)程會(huì)先在所在的 NUMA 節(jié)點(diǎn)上分配內(nèi)存,當(dāng)本地內(nèi)存不足時(shí),才會(huì)在遠(yuǎn)程分配內(nèi)存。如上圖所示,主機(jī)上包含兩個(gè) NUMA 節(jié)點(diǎn),其中每個(gè)節(jié)點(diǎn)都有 32GB 的內(nèi)存,但是當(dāng) MySQL InnoDB 的緩存池占用 48GB 的內(nèi)存時(shí),它會(huì)在 NUMA 節(jié)點(diǎn) 0 和 NUMA 節(jié)點(diǎn) 1 分別分配 32GB 和 16GB 的內(nèi)存。

雖然 48GB 的內(nèi)存遠(yuǎn)遠(yuǎn)沒有到達(dá)主機(jī) 64GB 的內(nèi)存上限,但是當(dāng)某些數(shù)據(jù)必須要在 NUMA 節(jié)點(diǎn) 0 的內(nèi)存上分配時(shí),就會(huì)導(dǎo)致 NUMA 節(jié)點(diǎn) 0 中的內(nèi)存被交換到了文件系統(tǒng)上為新的內(nèi)存請(qǐng)求讓出位置[^5],InnoDB 緩存池中內(nèi)存的頻繁換入和換出會(huì)使 MySQL 的查詢隨機(jī)地出現(xiàn)延遲,而一旦發(fā)生了交換分區(qū),可能就是性能螺旋下降的開始。

Linux 中的 zone_reclaim_mode 可以允許工程師設(shè)置在 NUMA 節(jié)點(diǎn)內(nèi)存不足時(shí)內(nèi)存的回收策略,在默認(rèn)情況下該模式都會(huì)處于關(guān)閉狀態(tài)[^6],如果我們?cè)?NUMA 系統(tǒng)中通過該配置啟用了激進(jìn)的內(nèi)存回收策略,可能會(huì)影響程序的性能[^7],MySQL 也會(huì)受到內(nèi)存回收策略的影響,但是僅僅關(guān)閉該策略并不會(huì)解決它遇到的頻繁觸發(fā)交換分區(qū)的問題[^8]。

  1. $ cat /proc/sys/vm/zone_reclaim_mode 

想要解決該問題,我們需要使用上一節(jié)提到的 numactl 將內(nèi)存的分配策略改為 interleave,使用該內(nèi)存分配策略會(huì)使得 MySQL 的內(nèi)存均勻地分配到不同的 NUMA 節(jié)點(diǎn)上,能夠降低頁(yè)面頻繁換入換出的可能性。

even-memory-node

 

圖 6 - 分配均勻的內(nèi)存

該問題并不是 MySQL 獨(dú)有的,很多占用大量?jī)?nèi)存的數(shù)據(jù)庫(kù)都會(huì)遇到上述問題,雖然使用 interleave 能夠暫時(shí)解決這些問題,但是 MySQL 進(jìn)程訪問遠(yuǎn)程內(nèi)存時(shí),與本地內(nèi)存相比仍然會(huì)遇到性能損失,想要一勞永逸地避免服務(wù)在 NUMA 上運(yùn)行的額外開銷,最好的辦法還是開發(fā)能夠感知底層 NUMA 架構(gòu)的應(yīng)用程序。以 MySQL 為例,Jeremy Cole 在文章中提出了如下的修改,可以更好地利用 NUMA 的本地內(nèi)存[^9]:

  • 將緩存池中的數(shù)據(jù)按照塊或者索引智能地分配到不同節(jié)點(diǎn)上;
  • 為正常的查詢線程保留默認(rèn)的分配策略,內(nèi)存還是會(huì)優(yōu)先分配本地節(jié)點(diǎn)上;
  • 將簡(jiǎn)單的查詢線程重新調(diào)度到能夠訪問本地內(nèi)存的節(jié)點(diǎn)上;

除了 MySQL 可以利用 NUMA 來提高性能之外,一些框架或者編程語(yǔ)言也可以通過感知底層的 NUMA 信息來提升服務(wù)的響應(yīng)速度,例如 Go 語(yǔ)言社區(qū)中就有關(guān)于 NUMA 感知調(diào)度的設(shè)計(jì)文檔[^10],雖然由于該特性的實(shí)現(xiàn)過于復(fù)雜,目前沒有投入到開發(fā)中,但是這仍然是調(diào)度器未來的發(fā)展方向。

總結(jié)

很多軟件工程師可能認(rèn)為操作系統(tǒng)以及底層的硬件與我們的距離非常遙遠(yuǎn),我們?cè)陂_發(fā)軟件時(shí)不需要考慮這么多細(xì)節(jié),對(duì)于絕大多數(shù)的應(yīng)用程序來說,這一點(diǎn)都是成立的,操作系統(tǒng)能夠?yàn)槲覀兤帘魏芏嗟讓拥膶?shí)現(xiàn)細(xì)節(jié),讓我們能夠?qū)⒏嗟木ν度氲綐I(yè)務(wù)邏輯的實(shí)現(xiàn)上。

不過正如我們?cè)谖恼轮刑岬降?,哪怕操作系統(tǒng)做出再多的隔離和抽象,物理世界存在的限制還是會(huì)在暗處影響我們的應(yīng)用程序,想要開發(fā)高性能的軟件必須要關(guān)注下兩層甚至更底層的實(shí)現(xiàn)細(xì)節(jié),NUMA 這種硬件層面的設(shè)計(jì)就會(huì)深刻的影響我們的軟件,這里再來回顧一下文章開頭提到的兩點(diǎn)影響:

  • NUMA 引入了本地內(nèi)存和遠(yuǎn)程內(nèi)存,CPU 訪問本地內(nèi)存的延遲會(huì)小于訪問遠(yuǎn)程內(nèi)存;
  • NUMA 的內(nèi)存分配與內(nèi)存回收策略結(jié)合時(shí)會(huì)可能會(huì)導(dǎo)致 Linux 的頻繁交換分區(qū)(Swap)進(jìn)而影響系統(tǒng)的穩(wěn)定性;

我們當(dāng)然更希望主機(jī)上的所有 CPU 都能夠快速地訪問全部的內(nèi)存,但是硬件的限制導(dǎo)致我們無法實(shí)現(xiàn)這么理想的情況,而 NUMA 可能是 CPU 架構(gòu)發(fā)展的必然方向,通過將 CPU 和內(nèi)存資源分組降低總線的壓力,讓單個(gè)主機(jī)容納很多的 CPU。到最后,我們還是來看一些比較開放的相關(guān)問題,有興趣的讀者可以仔細(xì)思考一下下面的問題:

NUMA 架構(gòu)最多可以支持多少 CPU?該架構(gòu)又存在哪些瓶頸?

 

MPP(Massive Parallel Processing)是如何擴(kuò)展系統(tǒng)的?它解決了哪些問題?

 

  • Optimizing Linux Memory Management for Low-latency / High-throughput Databases https://engineering.linkedin.com/performance/optimizing-linux-memory-management-low-latency-high-throughput-databases
  • NUMA (Non-Uniform Memory Access): An Overview https://queue.acm.org/detail.cfm?id=2513149
  • PostgreSQL, NUMA and zone reclaim mode on linux http://frosty-postgres.blogspot.com/2012/08/postgresql-numa-and-zone-reclaim-mode.html

本文轉(zhuǎn)載自微信公眾號(hào)「真沒什么邏輯」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系真沒什么邏輯公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 真沒什么邏輯
相關(guān)推薦

2023-09-20 14:54:17

MySQL

2013-09-26 09:34:56

女程序員

2020-06-23 14:20:08

5G網(wǎng)絡(luò)國(guó)家工業(yè)革命

2024-01-08 13:28:00

5G低延遲

2021-06-02 07:57:48

內(nèi)存管理

2020-06-10 14:10:53

服務(wù)開發(fā) 架構(gòu)

2015-06-10 10:50:29

程序員感覺到累

2019-09-26 09:49:10

程序員技術(shù)設(shè)計(jì)

2015-04-09 10:40:29

HTTP協(xié)議TCPHTTP事務(wù)延遲

2021-01-05 22:36:32

5G低延遲網(wǎng)絡(luò)

2016-08-19 01:59:22

APPAPM用戶

2022-04-13 20:53:15

Spring事務(wù)管理

2023-03-22 09:10:18

IT文檔語(yǔ)言

2014-03-05 14:58:00

蘋果CarPlayiOS

2015-12-07 10:49:43

卸載App用戶體驗(yàn)

2022-05-11 08:22:54

IO負(fù)載NFSOS

2021-01-25 07:14:53

Cloud DevOps云計(jì)算

2024-03-27 08:08:29

網(wǎng)絡(luò)延遲事務(wù)

2012-08-17 10:01:07

云計(jì)算

2020-03-30 15:05:46

Kafka消息數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)