現(xiàn)在的服務(wù)器物理機CPU一般都是多個CPU,核數(shù)也是十幾甚至幾十核珍语。內(nèi)存幾十GB甚至是上百G找都,也是由許多的內(nèi)存條組成的。那么我這里思考一下廊酣,這么多的CPU和內(nèi)存它們之間是怎么互相連接的能耻?同一個CPU核訪問不同的內(nèi)存條延時一樣嗎?
在《內(nèi)存隨機訪問也比順序慢亡驰,帶你深入理解內(nèi)存IO過程》中我們了解了內(nèi)存訪問時芯片內(nèi)部的執(zhí)行過程晓猛,在《實際測試內(nèi)存在順序IO和隨機IO時的訪問延時差異》中我們又進行了實際的代碼測試。不過這兩文中我們都把精力聚焦在內(nèi)存內(nèi)部機制凡辱,而回避了上面的問題戒职,那就是CPU和內(nèi)存的連接方式,也就是總線架構(gòu)透乾。
回顧CPU與內(nèi)存的簡單連接:FSB時代
我們先來回顧下在歷史上CPU洪燥、內(nèi)存數(shù)量比較少的年代里的總線方案-FSB磕秤。FSB的全稱是Front Side Bus,因此也叫前端總線捧韵。CPU通過FSB總線連接到北橋芯片市咆,然后再連接到內(nèi)存。內(nèi)存控制器是集成在北橋里的再来,Cpu和內(nèi)存之間的通信全部都要通過這一條FSB總線來進行蒙兰。
在這個年代里,當時提高計算機系統(tǒng)整體性能的方式就是不斷地提高CPU芒篷、FSB總線搜变、內(nèi)存條的數(shù)據(jù)傳輸頻率。
如今多CPU多內(nèi)存條復(fù)雜互聯(lián):NUMA時代
當CPU的主頻提升到了3GHz每秒以后针炉,硬件制造商們發(fā)現(xiàn)單個CPU的已經(jīng)到了物理極限了挠他。所以就改變了性能改進的方法,改成為向多核篡帕、甚至是多CPU的方向來發(fā)展殖侵。在這種情況下,如果仍然采用FSB總線赂苗,會導(dǎo)致所有的CPU和內(nèi)存通信都經(jīng)過總線愉耙,這樣總線就成為了瓶頸贮尉,無法充分發(fā)揮多核的優(yōu)勢與性能拌滋。所以CPU制造商們把內(nèi)存控制器從北橋搬到了CPU內(nèi)部,這樣CPU便可以直接和自己的內(nèi)存進行通信了猜谚。那么败砂,如果CPU想要訪問不和自己直連的內(nèi)存條怎么辦呢?所以就誕生了新的總線類型魏铅,它就叫QPI總線昌犹。
圖中CPU1如果想要訪問內(nèi)存3的話,就需要經(jīng)過QPS總線才可以览芳。
動手查看Linux下NUMA架構(gòu)
我們先通過dmidecode命令查看一下內(nèi)存插槽斜姥,單條大小等信息。大家可以試著在linux上執(zhí)行以下該命令沧竟。輸出結(jié)果很長铸敏,大家可以有空仔細研究。我這里不全部介紹悟泵,這里只挑選一些和內(nèi)存相關(guān)的:
# dmidecode|grep -P -A5 "Memory\s+Device"|grep Size
Size: 8192 MB
Size: 8192 MB
Size: No Module Installed
Size: 8192 MB
Size: No Module Installed
Size: 8192 MB
Size: 8192 MB
Size: 8192 MB
Size: No Module Installed
Size: 8192 MB
Size: No Module Installed
Size: 8192 MB
可以看出杈笔,我當前使用的機器上共有16個內(nèi)存插槽,共插了8條8G的內(nèi)存糕非。所以總共是64GB蒙具。如我們前面所述球榆,在NUMA架構(gòu)里,每一個物理CPU都有不同的內(nèi)存組禁筏,通過numactl
命令可以查看這個分組情況持钉。
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 12 13 14 15 16 17
node 0 size: 32756 MB
node 0 free: 19642 MB
node 1 cpus: 6 7 8 9 10 11 18 19 20 21 22 23
node 1 size: 32768 MB
node 1 free: 18652 MB
node distances:
node 0 1
0: 10 21
1: 21 10
通過上述命令可以看到,每一組CPU核分配了32GB(4條)的內(nèi)存融师。 node distance
是一個二維矩陣右钾,描述node訪問所有內(nèi)存條的延時情況。 node 0
里的CPU訪問node 0
里的內(nèi)存相對距離是10
,因為這時訪問的內(nèi)存都是和該CPU直連的旱爆。而node 0
如果想訪問node 1
節(jié)點下的內(nèi)存的話舀射,就需要走QPI總線了,這時該相對距離就變成了21
怀伦。
所以脆烟、在NUMA架構(gòu)下,CPU訪問自己同一個node里的內(nèi)存要比其它內(nèi)存要快房待!
動手測試NUMA架構(gòu)內(nèi)存延遲差異
numactl
命令有--cpubind
和--membind
的選項邢羔,通過它們我們可以指定我們要用的node節(jié)點。還沿用《用代碼讓你來實際感受內(nèi)存的在不同情況下的訪問延時差異》里的測試代碼
1桑孩、讓內(nèi)存和CPU處于同一個node
# numactl --cpubind=0 --membind=0 ./main
Delay (ns)
2k 8k 32k 128k 512k 2m 8m 32m 128m
s1 1.28 1.28 1.26 1.25 1.26 1.26 1.28 1.43 1.43
s32 1.27 1.26 1.32 1.78 2.67 2.73 3.27 9.95 10.37
s64 1.28 1.26 1.26 1.82 2.43 2.48 3.15 8.82 8.92
andom 2.40 2.40 2.40 2.40 4.80 4.80 19.20 28.80 52.80
2拜鹤、讓內(nèi)存和CPU處于不同node
# numactl --cpubind=0 --membind=1 ./main
Delay (ns)
2k 8k 32k 128k 512k 2m 8m 32m 128m
s1 1.29 1.28 1.26 1.26 1.26 1.26 1.31 1.62 1.63
s32 1.29 1.26 1.33 1.77 2.80 2.92 3.95 13.69 13.77
s64 1.30 1.27 1.26 1.82 2.47 2.48 3.96 12.93 12.90
andom 2.40 2.40 2.40 2.40 4.80 4.80 19.20 31.20 52.80
結(jié)論
通過上面的各個小節(jié)我們可以看到,現(xiàn)代的服務(wù)器里流椒,CPU和內(nèi)存條都有多個敏簿,它們之前目前主要采用的是復(fù)雜的NUMA架構(gòu)進行互聯(lián),NUMA把服務(wù)器里的CPU和內(nèi)存分組劃分成了不同的node宣虾。從上述實驗結(jié)果來看惯裕,拿8M數(shù)組,循環(huán)步長為64的case來說绣硝,同node耗時3.15納秒蜻势,跨node為3.96納秒。所以屬于同一個node里的CPU和內(nèi)存之間訪問速度會比較快鹉胖。而如果跨node的話握玛,則需要經(jīng)過QPI總線,總體來說甫菠,速度會略慢一些挠铲。
歡迎搜索微信公眾號:開發(fā)內(nèi)功修煉