天天看點

你不知道的記憶體知識

世界上最快的捷徑,就是腳踏實地,本文已收錄【 架構技術專欄 】關注這個喜歡分享的地方。

一、CPU與記憶體

先鋪墊幾個概念,以免後面混亂:

  • Socket或Processor: 指一個實體CPU晶片,盒裝還是散裝的。上面有很多針腳,直接安裝在主機闆上。
  • Core : 指在Processor裡封裝一個CPU核心,每個Core都是完全獨立的計算單元,我們平時說的4核心CPU,指的就是Processor裡面封裝了4個Core。
  • HT超線程: 目前Intel與AMD的Processor大多支援在一個Core裡并行執行兩個線程,此時從作業系統看就相當于兩個邏輯CPU(Logical Processor)。大多數情況下,我們程式裡提到的CPU概念就是指的這個Logical Processor。

咱們先來看幾個問題:

1、CPU可以直接操作記憶體嗎?

可能一大部分老鐵肯定會說:肯定的啊,不能操作記憶體怎麼讀取資料呢。

其實如果我們用這聰明的大腦想一想,咱們的台式主機大家肯定都玩過。上面CPU和記憶體條是兩個完全獨立的硬體啊,而且CPU也沒有任何直接插槽用于挂載記憶體條的。

也就是說,CPU和記憶體條是實體隔離的,CPU并不能直接的通路記憶體條,而是需要借助主機闆上的其他硬體間接的來實作通路。

2、CPU的運算速度和記憶體條的通路速度差距有多大?

呵呵呵,這麼說吧,就是一個鴻溝啊,CPU的運算速度與記憶體通路速度之間的差距是100倍。

而由于CPU與記憶體之間的速度差存在N個數量級的巨大鴻溝,于是CPU最親密的小夥伴Cache 閃亮登場了。與DRAM 家族的記憶體(Memory)不同,Cache來自SRAM家族。

而DRAM與SRAM的最簡單差別就是後者特别快,容量特别小,電路結構非常複雜,造價特别高。

而Cache與主記憶體之間的巨大性能差距主要還是工作原理與結構不同:

  • DRAM存儲一位資料隻需要一個電容加一個半導體,SRAM則需要6個半導體。
  • 由于DRAM的資料其實是被儲存在電容裡的,是以每次讀寫過程中的充放電環節也導緻了DRAM讀寫資料有一個延時的問題,這個延時通常為十幾到幾十ns。
  • 記憶體可以被看作一個二維數組,每個存儲單元都有其行位址和列位址。

由于SRAM的容量很小,是以存儲單元的位址(行與列)比較短,可以被一次性傳輸到SRAM中。DRAM則需要分别傳送行與列的位址。

  • SRAM的頻率基本與CPU的頻率保持一緻,而DRAM的頻率直到DDR4以後才開始接近CPU的頻率。

3、Cache 是怎麼使用的?

其實Cache 是被內建到CPU内部的一個存儲單元(平時也被我們稱為高速緩存),由于其造價昂貴,并且存儲容量遠遠不能滿足CPU大量、高速存取的需求。

是以出于對成本的控制,在現實中往往采用金字塔形的多級Cache體系來實作最佳緩存效果。

于是出現了,一級Cache(L1 Cache)、二級Cache(L2 Cache)及三級Cache(L3 Cache)。每一級都犧牲了部分性能名額來換取更大的容量,目的也是存儲更多的熱點資料。

以Intel家族Intel SandyBridge架構的CPU為例:

  • L1 Cache容量為64KB,通路速度為1ns左右
  • L2Cache容量擴大4倍,達到256KB,通路速度則降低到3ns左右
  • L3 Cache的容量則擴大512倍,達到32MB,通路速度也下降到12ns左右(也比通路主存的105ns(40ns+65ns)快一個數量級)

L3 Cache是被一個Socket上的所有CPU Core共享的,其實最早的L3 Cache被應用在AMD釋出的K6-III處理器上,當時的L3 Cache受限于制造技術,并沒有被內建到CPU内部,而是被內建在主機闆上,如圖:

從上圖我們也能看出來,CPU如果要通路記憶體中的資料,則需要經過L1、L2、L3三道關卡,就是這三個Cache中都沒有需要的資料,才會從主記憶體中直接進行讀取。

最後我們來看下Intel Sandy Bridge CPU的架構圖:

二、多核CPU與記憶體共享的問題

問題: Cache一緻性問題

多核CPU共享記憶體的問題也被稱為Cache一緻性問題。

其實就是多個CPU核心看到的Cache資料應該是一緻的,在某個資料被某個CPU寫入自己的Cache(L1 Cache)以後,其他CPU都應該能看到相同的Cache資料。

如果在自己的Cache中有舊資料,則抛棄舊資料。

考慮到每個CPU都有自己内部獨占的Cache,是以這個問題與分布式Cache保持同步的問題是同一類問題

目前業界公認的解決一緻性問題的最佳方案就是Intel 的MESI協定了,大多數SMP架構都采用了這一方案。

解決方案:MESI

不知道大家還記得Cache Line 嗎,就是我們常說的高速緩存中緩存條目裡面的那個緩存行。

其實仔細想想,在進行I/O操作從來不以位元組為機關,而是以塊為機關,有兩個原因:

  • I/O 操作比較慢,是以讀一個位元組與讀連續N個位元組的花費時間基本相同
  • 資料通路一般都具有空間連續的特征

是以CPU針對Memory的讀寫也采用了類似于I/O塊的方式

實際上,CPU Cache(高速緩存)裡最小的存儲單元就是Cache line(緩存行),Intel CPU 的一個Cache Line存儲64個位元組。

每一級Cache都被劃分為很多組Cache Line,典型的情況就是4條Cache Line為一組。

當Cache從Memory中加載資料時,一次加載一條Cache Line的資料

如圖我們可以看到,每個Cache Line 頭部都有兩個Bit來辨別自身狀态,總共四種:

  • M(Modified):修改狀态,在其他CPU上沒有資料的副本,并且在本CPU上被修改過,與存儲器中的資料不一緻,最終必然會引發系統總線的寫指令,将Cache Line中的資料寫回Memory中。
  • E(Exclusive):獨占狀态,表示目前Cache Line中的資料與Memory中的資料一緻,此外,在其他CPU上沒有資料的副本。
  • S(Shared):共享狀态,表示Cache Line中的資料與Memory中的資料一緻,而且目前CPU至少在其他某個CPU中有副本。
  • I(Invalid):無效狀态,在目前Cache Line中沒有有效資料或者該Cache Line資料已經失效,不能再用;當Cache要加載新資料時,優先選擇此狀态的Cache Line,此外,Cache Line的初始狀态也是I狀态

在對Cache(高速緩存)的讀寫操作引發了Cache Line(緩存行)的狀态變化,因而可以将其了解為一種狀态機模型。

但MESI的複雜和獨特之處在于狀态有兩種視角:

  • 一種是目前讀寫操作(Local Read/Write)所在CPU看到的自身的Cache Line狀态及其他CPU上對應的Cache Line狀态
  • 另一種是一個CPU上的Cache Line狀态的變遷會導緻其他CPU上對應的Cache Line狀态變遷。

如下所示為MESI協定的狀态圖:

具體MESI的實作過程可以看我另一篇文章:

看懂這篇,才能說了解并發底層技術

深入了解不一緻性記憶體

MESI協定解決了多核CPU下的Cache一緻性問題,因而成為SMP架構的唯一選擇,而SMP架構近幾年迅速在PC領域(X86)發展。

SMP架構是一種平行的架構,所有CPU Core都被連接配接到一個記憶體總線上,它們平等通路記憶體,同時整個記憶體是統一結構、統一尋址的。

如下所示給出了SMP架構的示意圖:

随着CPU核心數量的不斷增加,SMP架構也暴露出天生的短闆,其根本瓶頸是共享記憶體總線的帶寬無法滿足CPU數量的增加,同時,在一條“馬路”上通行的“車”多了,難免會陷入“擁堵模式”。

不知道你是否聽說過總線風暴,可以看下:

總線風暴

在這種情況下,分布式解決方案應運而生,系統的記憶體與CPU進行分割并捆綁在一起,形成多個獨立的子系統,這些子系統之間高速互聯,這就是NUMA(None Uniform Memory Architecture)架構,如下圖所示。

可以看出,NUMA架構中的記憶體被分割為獨立的幾塊,被不同CPU私有化了。

是以在CPU通路自家記憶體的時候會非常快,在通路其他CPU控制的記憶體資料時,則需要通過内部互聯通道通路。

NUMA架構的優點就是其伸縮性,就算擴充到幾百個CPU也不會導緻性嚴重的下降。

NUMA技術的特點

在NUMA架構中引入了一個重要的新名詞——Node

一個Node由一個或者多個Socket Socket組成,即實體上的一個或多個CPU晶片組成一個邏輯上的Node

我們來看一個Dell PowerEdge系列伺服器的NUMA的架構圖:

從上圖可以看出其特點:

  • 4個處理器形成4個獨立的NUMA Node由于每個Node都為8 Core,支援雙線程
  • 每個Node裡的Logic CPU數量都為16個,占每個Node配置設定系統總記憶體的1/4
  • 每個Node之間都通過Intel QPI(QuickPath Interconnect)技術形成了點到點的全互聯處理器系統

NUMA這種基于點到點的全互聯處理器系統與傳統的基于共享總線的處理器系統的SMP還是有巨大差異的。

在這種情況下無法通過嗅探總線的方式來實作Cache一緻性,是以為了實作NUMA架構下的Cache一緻性,Intel引入了MESI協定的一個擴充協定——MESIF

針對NUMA的支援

NUMA架構打破了傳統的“全局記憶體”概念,目前還沒有任意一種程式設計語言從記憶體模型上支援它,目前也很難開發适應NUMA的軟體。

Java在支援NUMA的系統裡,可以開啟基于NUMA的記憶體配置設定方案,使得目前線程所需的記憶體從對應的Node上配置設定,進而大大加快對象的建立過程

在大資料領域,NUMA系統正發揮着越來越強大的作用,SAP的高端大資料系統HANA被SGI在其UV NUMA Systems上實作了良好的水準擴充

在雲計算與虛拟化方面,OpenStack與VMware已經支援基于NUMA技術的虛機配置設定能力,使得不同的虛機運作在不同的Core上,同時虛機的記憶體不會跨越多個NUMA Node