“了解高并發(fā)底層原理”,面試官:講一下MESI(緩存一致性協(xié)議)吧
前言:
JVM不是真實存在的,只是一個抽象的概念。volatile關鍵字底層也是借助MESI緩存一致性協(xié)議和內存屏障得以實現有序性和可見性的。
MESI是計算機底層的協(xié)議,
所有支持高并發(fā)的編程語言的底層都是基于MESI協(xié)議來保證并發(fā)安全的,
所以MESI協(xié)議更有助于我們去理解底層原理,知其所以然!
本期圍繞著,什么是(Who),為何來(How),是什么(What),這三點內容來進行講解該協(xié)議。
1.什么是(Who):
MESI(Modified Exclusive Shared Or Invalid)協(xié)議是基于Invalidate的高速緩存一致性協(xié)議,并且是支持回寫高速緩存的最常用協(xié)議之一。 它也被稱為伊利諾伊州協(xié)議(由于其在伊利諾伊大學厄巴納 - 香檳分校的發(fā)展)。用于解決緩存一致的問題。
2.為何來(How):
2.1緩存不一致帶來的后果
如上圖,數據加載的流程如下:(從內存到寄存器)
將程序和數據從硬盤加載到內存中
將程序和數據從內存加載到緩存中(目前多三級緩存,數據加載順序:L3->L2->L1)
CPU將緩存中的數據加載到寄存器中,并進行運算
CPU會將數據刷新回緩存,并在一定的時間周期之后刷新回內存
現在的CPU基本都是
多核
CPU,服務器更是提供了多CPU的支持,而每個核心也都有自己獨立的緩存,當多個核心同時操作多個線程對同一個數據進行更新時,如果核心2在核心1還未將更新的數據刷回內存之前讀取了數據,并進行操作,就會造成程序的執(zhí)行結果造成隨機性的影響,舉個例子如下:
如果由兩個cpu同事開始讀取了int i =0,然后同同時執(zhí)行如下語句,會出現如下情況:
...... int i = 0; i++; ......
剛開始,i初始化為0,假設有兩個線程A,B,
A線程在CPU0上進行執(zhí)行,從主存加載i變量的數值到緩存,然后從緩存中加載到寄存器中,在寄存器中執(zhí)行i+1操作,得到i的值為1,
此時得到i等于1的值還存放在CPU0的緩存中;
由于線程A計算i等于1的值還存放在緩存中,還沒有刷新會內存,此時線程B執(zhí)行在CPU1上,從內存中加載i的值,此時i的值還是0,然后進行i+1操作,得到i的值為1,存到CPU1的緩存中,
A,B線程得到的值都是1,在一定的時間周期之后刷新回內存
4.寫回內存后,兩次i++操作之后,其值還是1;
可以看到雖然我們做了兩次++i操作,但是只進行了一次加1操作,這就是緩存不一致帶來的后果。
2.2解決方法:
在先前的解決方案中,大致有兩種思路:
總線加鎖的方式:
先前大佬們提供了一種總線加鎖的方式,而總線加鎖是對整個內存進行加鎖,在一個核心對一個數據進行修改的過程中,其他的核心也無法修改內存中的其他數據,這樣對導致CPU處理性能嚴重下降。
總線加鎖的方式導致CPU性能嚴重下降,此時我們提出了緩存一致性協(xié)議(MESI):
緩存一致性協(xié)議提供了一種高效的內存數據管理方案,它只會對單個緩存行(緩存行是緩存中數據存儲的基本單元)的數據進行加鎖,不會影響到內存中其他數據的讀寫。
cache line,緩存行是為了簡化與RAM之間的通信,高速緩存控制器是針對數據塊,而不是字節(jié)進行操作的。從程序設計的角度講,高速緩存其實就是一組稱之為緩存行(cache line)的固定大小的數據塊。
因此,我們引入了緩存一致性協(xié)(MESI)議來對內存數據的讀寫進行管理。
3.是什么(What)
3.1數據在緩存中的四種狀態(tài):
MESI的英文全程為:Modified Exclusive Shared Or Invalid,有四種狀態(tài),分別對應其英文單詞,如下:
3.2MESI的六種消息(請求消息和響應消息)
cpu接收響應消息的順序決定了其他cpu感知到的當前線程的執(zhí)行順序
read:(請求消息)
“read” 消息用來獲取指定物理地址上的 cache line(如果在緩存中,從緩存中取,不在緩存中則從內存中取) 數據。
read response:(響應消息)
"read response"消息包含先前“read”消息請求的數據。此“read response”消息可能來自內存或其他CPU的緩存。
invalidate:(請求消息)
Invalidate。該消息將其他 CPU cache 中指定的數據設置為失效。該消息攜帶物理地址,其他 CPU cache 在收到該消息后,必須進行匹配,發(fā)現在自己的 cache line 中有該地址的數據,那么就將其從 cahe line 中移除,并響應 Invalidate Acknowledge 回應。
invalidate acknowledge:(響應消息)
該消息用做回應 Invalidate 消息。
read invalidate:(請求消息)
該消息中帶有物理地址,用來說明想要讀取哪一個 cache line 中的數據,同時指示其他緩存刪除數據。可以看作是 read + Invalidate 消息的組合,“read invalidate”消息需要“read response”和一組“invalidate acknowledge”消息作為應答。
writeback:
“writeback”消息包含要寫回內存的地址和數據(也可能是沿途“窺探”到其他cpu的緩存中)。該消息用在 modified 狀態(tài)的 cache line 被置換時發(fā)出,用來將最新的數據寫回 memory 或其他下一級 cache 中。
3.3MESI四種狀態(tài)通過六種消息進行轉換(利用3.1與3.2章節(jié)的知識點)
上圖的轉換詳細說明:
a
cache 通過 writeback 將數據回寫到 memory 或者下一級 cache 中。這時候狀態(tài)由 modified 變成了 exclusive 。
b
cpu 直接將數據寫入 cache line ,導致狀態(tài)變?yōu)榱?modified 。
c
CPU 收到一個 read invalidate 消息,該消息中帶有物理地址,用來說明想要讀取哪一個 cache line 中的數據,同時指示其他緩存刪除數據。此時 CPU 必須將對應 cache line 設置成 invalid 狀態(tài) , 并且響應一個 read response 消息和 invalidate acknowledge 消息。
d
CPU 需要執(zhí)行一個原子的 readmodify-write 操作,并且其 cache 中沒有緩存數據。這時候 CPU 就會在總線上發(fā)送一個 read invalidate 消息來請求數據,并試圖獨占該數據。CPU 可以通過收到的 read response 消息獲取到數據,并等待所有的 invalidate acknowledge 消息,然后將狀態(tài)設置為 modifie 。
e
CPU需要執(zhí)行一個原子的readmodify-write操作,并且其local cache中有read only的緩存數據(cacheline處于shared狀態(tài)),這時候,CPU就會在總線上發(fā)送一個invalidate請求其他cpu清空自己的local copy,以便完成其獨自霸占對該數據的所有權的夢想。同樣的,該cpu必須收集所有其他cpu發(fā)來的invalidate acknowledge之后才能更改狀態(tài)為 modified。
f
在本cpu獨自享受獨占數據的時候,其他的cpu發(fā)起read請求,希望獲取數據,這時候,本cpu必須以其local cacheline的數據回應,并以read response回應之前總線上的read請求。這時候,本cpu失去了獨占權,該cacheline狀態(tài)從Modified狀態(tài)變成shared狀態(tài)(有可能也會進行寫回的動作)。
g
這個遷移和f類似,只不過開始cacheline的狀態(tài)是exclusive,cacheline和memory的數據都是最新的,不存在寫回的問題。總線上的操作也是在收到read請求之后,以read response回應。
h
需要發(fā)送invalidate以通知其他cpu相應數據將要失效,并等待其他cpu的回應消息(invalidate acknowledge)。
i
其他的CPU進行一個原子的read-modify-write操作,但是,數據在本cpu的cacheline中,因此,其他的那個CPU會發(fā)送read invalidate,請求對該數據以及獨占權。本cpu回送read response”和“invalidate acknowledge”,一方面把數據轉移到其他cpu的cache中,另外一方面,清空自己的cacheline。
j
cpu想要進行write的操作但是數據不在local cache中,因此,該cpu首先發(fā)送了read invalidate啟動了一次總線transaction。在收到read response回應拿到數據,并且收集所有其他cpu發(fā)來的invalidate acknowledge之后(確保其他cpu沒有l(wèi)ocal copy),完成整個bus transaction。當write操作完成之后,該cacheline的狀態(tài)會從Exclusive狀態(tài)遷移到Modified狀態(tài)。
k
本CPU執(zhí)行讀操作,發(fā)現local cache沒有數據,因此通過read發(fā)起一次bus transaction,來自其他的cpu local cache或者memory會通過read response回應,從而將該 cache line 從Invalid狀態(tài)遷移到shared狀態(tài)。
l
當cache line處于shared狀態(tài)的時候,說明在多個cpu的local cache中存在副本,因此,這些cacheline中的數據都是read only的,一旦其中一個cpu想要執(zhí)行數據寫入的動作,必須先通過invalidate獲取該數據的獨占權,而其他的CPU會以invalidate acknowledge回應,清空數據并將其cacheline從shared狀態(tài)修改成invalid狀態(tài)。
Java 緩存
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。