緩存一致性與MESI協議Snoop操作


參考博文:https://www.cnblogs.com/luoahong/p/11358997.html

一、緩存一致性問題指的是什么

在這兩個CPU核心里,1號核心要寫一個數據到內存里。這個怎么理解呢?我拿一個例子來給你解釋。

比方說,iPhone降價了,我們要把iPhone最新的價格更新到內存里。為了性能問題,它采用了上一講我們說的寫回策略,

1、先把數據寫入到L2 Cache里面,然后把Cache Block標記成臟的。這個時候,數據其實並沒有被同步到L3 Cache或者主內存里

2、1號核心希望在這個Cache Block要被交換出去的時候,數據才寫入到主內存里。

3、如果我們的CPU只有1號核心這一個CPU核,那這其實是沒有問題的。不過,我們旁邊還有一個2號核心呢!

4、這個時候,2號核心嘗試從內存里面去讀取iPhone的價格,結果讀到的是一個錯誤的價格。這是因為,iPhone的價格剛剛被1號核心更新過。
但是這個更新的信息,只出現在1號核心的L2 Cache里,而沒有出現在2號核心的L2 Cache或者主內存里面。

這個問題,就是所謂的緩存一致性問題,1號核心和2號核心的緩存,在這個時候是不一致的。

二、寫傳播

為了解決這個緩存不一致的問題,我們就需要有一種機制,來同步兩個不同核心里面的緩存數據。那這樣的機制需要滿足什么條件呢?我覺得能夠做到下面兩點就是合理的。

第一點叫 寫傳播(Write Propagation)。寫傳播是說,在一個CPU核心里,我們的Cache數據更新,必須能夠傳播到其他的對應節點的Cache Line里。

既然我們數據寫完了,自然要同步到其他CPU核的Cache里

三、事務的串行化

第二點叫 事務的串行化(Transaction Serialization),事務串行化是說,我們在一個CPU核心里面的讀取和寫入,在其他的節點看起來,順序是一樣的。

我們還拿剛才修改iPhone的價格來解釋。這一次,我們找一個有4個核心的CPU。1號核心呢,先把iPhone的價格改成了5000塊。差不多在同一個時間,2號核心把iPhone的價格改成了

這里兩個修改,都會傳播到3號核心和4號核心差不多在同一個時間,2號核心把iPhone的價格改成了6000塊。

1、然而這里有個問題,3號核心先收到了2號核心的寫傳播,再收到1號核心的寫傳播。所以3號核心看到的iPhone價格是先變成了6000塊,再變成了5000塊。
2、而4號核心呢,是反過來的,先看到變成了5000塊,再變成6000塊。雖然寫傳播是做到了,但是各個Cache里面的數據,是不一致的。

事實上,我們需要的是,從1號到4號核心,都能看到相同順序的數據變化。比如說,都是先變成了5000塊,再變成了6000塊。這樣,我們才能稱之為實現了事務的串行化。

事務的串行化,不僅僅是緩存一致性中所必須的。比如,我們平時所用到的系統當中,最需要保障事務串行的就是數據庫。多個不同的連接去訪問數據庫的時候,
化我們必須保障事務的串行化,做不到事務的串行化的數據庫,根本沒法作為可靠的商業數據庫來使用。

而在CPU Cache里做到事務串行化,需要做到兩點:

1、是一個CPU核心對於數據的操作,需要同步通信給到其他CPU核心。
2、如果兩個CPU核心里有同一個數據的Cache,那么對於這個Cache數據的更新,需要有一個“鎖”的概念。只有拿到了對應Cache Block的“鎖”之后,才能進行對應的數據更新。

接下來,我們就看看實現了這兩個機制的MESI協議。

四、總線嗅探

要解決緩存一致性問題,首先要解決的是多個CPU核心之間的數據傳播問題。最常見的一種解決方案呢,叫作 總線嗅探(Bus Snooping)。
這個名字聽起來,你多半會很陌生,但是其實特很好理解。

這個策略,本質上就是把所有的讀寫請求都通過總線(Bus)廣播給所有的CPU核心,然后讓各個核心去“嗅探”這些請求,再根據本地的情況進行響應。

總線本身就是一個特別適合廣播進行數據傳輸的機制,所以總線嗅探這個辦法也是我們日常使用的IntelCPU進行緩存一致性處理的解決方案。
關於總線這個知識點,我們會放在后面的I/O部分更深入地進行講解,這里你只需要了解就可以了。

五、寫失效協議

基於總線嗅探機制,其實還可以分成很多種不同的緩存一致性協議。不過其中最常用的,就是今天我們要講
的MESI協議。和很多現代的CPU技術一樣,MESI協議也是在Pentium時代,被引入到Intel CPU中的。

MESI協議,是一種叫作 寫失效(Write Invalidate)的協議。在寫失效協議里:

1、只有一個CPU核心負責寫入數據,
2、其他的核心,只是同步讀取到這個寫入。在這個CPU核心寫入Cache之后,它會去廣播一個“失效”請求告訴所有其他的CPU核心。
3、其他的CPU核心,只是去判斷自己是否也有一個“失效”版本的CacheBlock,然后把這個也標記成失效的就好了。

六、寫廣播協議

相對於寫失效協議,還有一種叫作 寫廣播(Write Broadcast)的協議。

1、一個寫入請求廣播到所有的CPU核心,同時更新各個核心里的Cache。寫廣播在實現上自然很簡單,
2、但是寫廣播需要占用更多的總線帶寬。
  寫失效只需要告訴其他的CPU核心,哪一個內存地址的緩存失效了,
  但是寫廣播還需要把對應的數據傳輸給其他CPU核心

七、Cache Line的四個不同的標記

做不到事務串行話的數據庫,根本沒法作為可靠的商業書庫看來使用

M:代表已修改(Modified)
E:代表獨占(Exclusive)
S:代表共享(Shared)
I:代表已失效(Invalidated)

“已修改”和“已失效”

1、這兩個狀態比較容易理解。所謂的“已修改”,就是我們上一講所說的“臟”的Cache Block。Cache Block里面的內容我們已經更新過了,
但是還沒有寫回到主內存里面。
2、而所謂的“已失效“,自然是這個Cache Block里面的數據已經失效了,我們不可以相信這個Cache Block里面的數據。

“獨占”和“共享”這兩個狀態。

這就是MESI協議的精華所在了。無論是獨占狀態還是共享狀態,緩存里面的數據都是“干凈”的。這個“干凈”,自然對應的是前面所說的“臟”的,也就是
說,這個時候,Cache Block里面的數據和主內存里面的數據是一致的。

“獨占”和“共享”這兩個狀態的差別在哪里呢?

這個差別就在於,在獨占狀態下,對應的Cache Line只加載到了當前CPU核所擁有的Cache里。其他的CPU核,並沒有加載對應的數據到自己的Cache里。這個
時候,如果要向獨占的Cache Block寫入數據,我們可以自由地寫入數據,而不需要告知其他CPU核。

在獨占狀態下的數據

如果收到了一個來自於總線的讀取對應緩存的請求,它就會變成共享狀態。這個共享狀態是因為,這個時候,另外一個CPU核心,也把對應的Cache Block,從內存里面加載到了自己的Cache里來。

而在共享狀態下

因為同樣的數據在多個CPU核心的Cache里都有。所以,當我們想要更新Cache里面的數據的時候,不能直接修改,而是要先向所有的其他CPU核心廣播一個請求,要求先把其他CPU核心里面的Cache,都變成無效的狀態,然后再更新當前Cache里面的數據。這個廣播操作,一般叫作RFO(Request
For Ownership),也就是獲取當前對應Cache Block數據的所有權。

有沒有覺得這個操作有點兒像我們在多線程里面用到的讀寫鎖。在共享狀態下,大家都可以並行去讀對應的數據。但是如果要寫,我們就需要通過一個鎖,獲取當前寫入位置的所有權。

整個MESI的狀態,可以用一個有限狀態機來表示它的狀態流轉。需要注意的是,對於不同狀態觸發的事件操作,可能來自於當前CPU核心,也可能來自總線里其他CPU核心廣播出來的信號。我把對應的狀態機流轉

圖放在了下面,你可以對照着Wikipedia里面MESI的內容,仔細研讀一下。

八、總結延伸

好了,關於CPU Cache的內容,我們介紹到這里就結束了。我們來總結一下。這一節,我們其實就講了兩塊兒內容,一個是緩存一致性,另一個是MESI協議。

想要實現緩存一致性,關鍵是要滿足兩點。第一個是寫傳播,也就是在一個CPU核心寫入的內容,需要傳播到其他CPU核心里。
更重要的是第二點,保障事務的串行化,才能保障我們的數據是真正一致的,我們的程序在各個不同的核心上運行的結果也是一致的。
這個特性不僅在CPU的緩存層面很重要,在數據庫層面更加重要。

之后,我介紹了基於總線嗅探機制的MESI協議。MESI協議是一種基於寫失效的緩存一致性協議。寫失效的協議的好處是,我們不需要在總線上傳輸數據內容,
而只需要傳輸操作信號和地址信號就好了,不會那么占總線帶寬。

MESI協議,是已修改、獨占、共享以及已失效這四個縮寫的合稱。獨占和共享狀態,就好像我們在多線程應用開發里面的讀寫鎖機制,確保了我們的緩存一致性。
而整個MESI的狀態變更,則是根據來自自己CPU核心的請求,以及來自其他CPU核心通過總線傳輸過來的操作信號和地址信息,進行狀態流轉的一個有限狀態機。

九、附錄MOSEI介紹

MOSEI

- MOESI協議引入了一個O(Owned)狀態,並在MESI協議的基礎上,進行了重新定義了S狀態,而E、M和I狀態和MESI協議的對應狀態相同。

  1. O位。O位為1表示在當前Cache 行中包含的數據是當前處理器系統最新的數據拷貝,而且在其他CPU中一定具有該Cache行的副本,其他CPU的Cache行狀態為S。如果主存儲器的數據在多個CPU的Cache中都具有副本時,有且僅有一個CPU的Cache行狀態為O,其他CPU的Cache行狀態只能為S。與MESI協議中的S狀態不同,狀態為O的Cache行中的數據與存儲器中的數據並不一致。
  2. S位。在MOESI協議中,S狀態的定義發生了細微的變化。當一個Cache行狀態為S時,其包含的數據並不一定與存儲器一致。如果在其他CPU的Cache中不存在狀態為O的副本時,該Cache行中的數據與存儲器一致;如果在其他CPU的Cache中存在狀態為O的副本時,Cache行中的數據與存儲器不一致。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM