探索底層的意義
話說人們?cè)?870年左右開始應(yīng)用黃色火藥,在1900年左右開始大量普及電動(dòng)地鐵答憔,并建成了埃菲爾鐵塔(1898)等偉大工程味赃,但是軍事技術(shù)的發(fā)展、革新最多的僅是二戰(zhàn)前后的1936到1945的這幾年時(shí)間虐拓,現(xiàn)在的軍事技術(shù)也大都僅是對(duì)二戰(zhàn)時(shí)的軍事技術(shù)體系的深化心俗,如自動(dòng)步槍,噴氣引擎侯嘀,潛艇另凌,坦克和反坦克等等谱轨。所以我們認(rèn)為,高強(qiáng)度的行業(yè)競爭吠谢,帶來其領(lǐng)域技術(shù)的深入發(fā)展土童,而因其深入的發(fā)展,其中的許多設(shè)計(jì)理念和產(chǎn)出工坊,往往惠及了很多的民用領(lǐng)域献汗,如復(fù)雜的渦輪增壓技術(shù)是二戰(zhàn)戰(zhàn)斗機(jī)的標(biāo)配,現(xiàn)在也經(jīng)過簡化王污,惠及到民用汽車領(lǐng)域罢吃。
而現(xiàn)在信息技術(shù)領(lǐng)域中白熱化的競爭莫過于Intel和AMD之間的藍(lán)紅之爭,其競爭讓CPU的設(shè)計(jì)和架構(gòu)經(jīng)過千錘百煉昭齐,是一個(gè)現(xiàn)代人類設(shè)計(jì)和實(shí)踐的結(jié)晶尿招。因此我們探究一下CPU底層的實(shí)現(xiàn),其中的思路和理念阱驾,特別是現(xiàn)在多核心CPU的設(shè)計(jì)就谜,也會(huì)對(duì)我們的高性能系統(tǒng),以及分布式系統(tǒng)有的設(shè)計(jì)和使用有很多借鑒和幫助里覆。
另外其實(shí)人們也發(fā)現(xiàn)往往一些帶有分形的東西丧荐,其不僅廣泛存在,而且也代表著很多我們未知的合理結(jié)構(gòu)喧枷,如人們所說的黃金分割虹统,宇宙及黑洞等,其也都和分形有關(guān)聯(lián)隧甚,分形可以簡單理解為不斷深入的底層構(gòu)成车荔,和其上層構(gòu)成有結(jié)構(gòu)上的相似。因此我們探究底層的設(shè)計(jì)呻逆,也對(duì)我們上層系統(tǒng)的設(shè)計(jì)有一定的參考和指導(dǎo)作用夸赫。
CPU的緩存結(jié)構(gòu)簡介
如下圖所示是Intel的Skylake的CPU架構(gòu),我們可以看到緩存被分為L1咖城、L2茬腿、L3這3層,CPU在運(yùn)行中首先使用自己的寄存器宜雀,然后使用速度更快的L1緩存切平,其中:L1D緩存數(shù)據(jù);L1I緩存指令辐董;L1緩存和次快的L2同步數(shù)據(jù)悴品;L2緩存和L3緩存同步數(shù)據(jù)(這里L(fēng)2和L3按照內(nèi)核數(shù)量做了等分,分給各個(gè)內(nèi)核使用),我們可以簡單地認(rèn)為L3和內(nèi)存同步數(shù)據(jù)苔严。
為什么會(huì)有這么多級(jí)的緩存呢定枷?因?yàn)槊考?jí)緩存的速度差異很大,越快的緩存容量越小届氢,因此CPU把緩存分成多級(jí)欠窒,每一級(jí)作為上一級(jí)的緩存。(其實(shí)在多核的情況下訪問緩存會(huì)有一些同步問題退子,我們?cè)谙挛挠懻摚?/p>
CPU的緩存性能參考
而我們可以認(rèn)為目前CPU的緩存性能差異如表所示(參考了卡耐基梅隆大學(xué)在2014年的教案等)岖妄。
在上表中要注意以下內(nèi)容:
1. L1、L2寂祥、L3的最小讀寫單位是64bit(8字節(jié))荐虐。
2. L2的周期已包含L1(miss)的周期,L3的周期已包含L2(miss)的周期丸凭。
3. 內(nèi)存訪問應(yīng)該還有TLB(虛擬地址頁表緩存)的miss的情況福扬,會(huì)增加少量周期。
4. 其實(shí)CPU的寄存器的整體大小為2KB左右惜犀,在64位下除了RAX忧换、RBX、RCX向拆、RDX、RSI酪耳、RDI浓恳、RSP、RBP碗暗、R8-R15這16個(gè)通用寄存器颈将,如Intel還大概有:MMX:80bit X 8,ZMM(YMM,XMM):512bit X 32等寄存器言疗,還有控制:64bit X 16晴圾,調(diào)試:64bit X 16,以及其他零散分類下及系統(tǒng)自用的若干噪奄。
因?yàn)檫@些緩存和內(nèi)存在性能上的差異死姚,所以對(duì)CPU的密集運(yùn)算則是越少訪問內(nèi)存越好,比如在發(fā)生一次CAS操作時(shí)勤篮,如果這個(gè)內(nèi)存訪問能命中L2緩存都毒,則還是比較高效的;但是如果L2 miss 連同 L3 miss 碰缔,則會(huì)變成一次讀內(nèi)存的重操作账劲,影響并發(fā)的性能(約100ns的耗時(shí)),同理,對(duì)于正常的鎖的操作瀑焦,緩存miss時(shí)會(huì)耗時(shí)較多(約200ns的耗時(shí))腌且。
當(dāng)前CPU的架構(gòu)圖
下面是Intel的Skylake 的架構(gòu)圖,與Sandy Bridge 的架構(gòu)圖榛瓮,和AMD的ZEN 的架構(gòu)圖铺董。
Intel和AMD的CPU的架構(gòu)圖雖然看著差異挺大,但它們的大結(jié)構(gòu)其實(shí)是一樣的榆芦,大概都分為3個(gè)模塊柄粹。
1. 前端執(zhí)行(front end):對(duì)應(yīng)Intel圖的上面及對(duì)應(yīng)AMD圖上面;這個(gè)是L1指令cache處理指令解碼(DECODE)匆绣,分支預(yù)測(cè)驻右,執(zhí)行隊(duì)列,調(diào)度器崎淳,等這些指令功能堪夭。
2. 計(jì)算:對(duì)應(yīng)INTEL圖的左下及對(duì)應(yīng)AMD圖的中間;這個(gè)就是整數(shù)計(jì)算單元和浮點(diǎn)計(jì)算單元拣凹。
3. 緩存/內(nèi)存:對(duì)應(yīng)INTEL圖的右下及對(duì)應(yīng)AMD圖的下面森爽;這個(gè)就是內(nèi)存控制器(內(nèi)存讀寫控制器及隊(duì)列,以及TLB(內(nèi)存頁表的虛擬地址轉(zhuǎn)換緩存))及L1數(shù)據(jù)緩存和L2緩存嚣镜。
從這些圖上我們可以看出爬迟,L1命令緩存AMD的Zen是64KB,而Intel是32KB菊匿;L2緩存AMD的Zen是512KB付呕,Intel是256KB,這個(gè)和CPU型號(hào)也有關(guān)系跌捆,但還是說明同一代下AMD的CPU在一些配置上更優(yōu)一些徽职。
這里也說下,網(wǎng)上流傳說佩厚,在AMD的Zen之前Intel的CPU的強(qiáng)大的浮點(diǎn)功能(以及除法器)姆钉,是Intel在跑分上勝利的其中一個(gè)重要因素,AMD認(rèn)為都有顯卡了抄瓦,顯卡浮點(diǎn)計(jì)算的能力非常強(qiáng)大潮瓶,因此CPU不需要太強(qiáng)的浮點(diǎn)功能了……。
再有我們?cè)诳碅MD的PPT時(shí)會(huì)發(fā)現(xiàn)钙姊,除了L1數(shù)據(jù)緩存到寄存器堆(register
file)還有個(gè)AGU到load/store queues模塊的箭頭筋讨,這里可能感覺比較奇怪,其實(shí)這個(gè)AGU的組件AMD和Intel都有摸恍,Intel的沒有畫出(之前的架構(gòu)PPT里有悉罕,現(xiàn)在應(yīng)該屬于Load Store Data這赤屋,但沒有畫出),這個(gè)全稱是Address Generation Unit壁袄,用來加速計(jì)算實(shí)際的物理地址类早,以及計(jì)算數(shù)組中的地址等。(另外嗜逻,其實(shí)大家知道應(yīng)用程序中的內(nèi)存地址對(duì)CPU和操作系統(tǒng)來講都是比較麻煩的虛擬地址)涩僻。下圖是AMD的緩存/內(nèi)存單元單元的一個(gè)展開圖(圖中L1數(shù)據(jù)緩存上的To Ex是到整數(shù)計(jì)算單元,To Fp是到浮點(diǎn)計(jì)算單元)栈顷。如圖
CPU緩存的使用
上面介紹了CPU整體的架構(gòu)圖逆日,以及緩存在CPU架構(gòu)圖中的位置,這里先介紹下CPU在單核環(huán)境下的多級(jí)緩存的架構(gòu)萄凤。
現(xiàn)在CPU都流行多核芯的架構(gòu)室抽,而我們先看其中的一個(gè)核心對(duì)緩存操作的流程,我們可以整體認(rèn)為:當(dāng)核心(Core)訪問(讀或?qū)懀㎜1緩存時(shí)沒有命中(miss)則訪問L2緩存和L3緩存靡努,在L3緩存也沒有命中時(shí)才操作內(nèi)存坪圾。多級(jí)緩存在獨(dú)占(exclusive)模式下,L1緩存中通過LRU策略逐出的數(shù)據(jù)會(huì)到L2,在L2中逐出的會(huì)到L3,在L3中逐出的有寫入/修改的數(shù)據(jù)則同步到內(nèi)存惑朦。
緩存的操作的最小單元我們可以叫緩存單元兽泄,英文是cache line,每個(gè)緩存單元緩存64bit(8Byte)的數(shù)據(jù)漾月,訪問緩存時(shí)通過內(nèi)存單元的物理地址病梢。另外我們常看到8WAY梁肿,16WAY這種來描述緩存飘千,其實(shí)緩存的在使用時(shí)是個(gè)類似二維數(shù)組的形式,這里的列就是WAY栈雳,如8WAY,就是8列缔莲。訪問時(shí)通過物理地址的高位和中位從列(WAY)和行(SET)中命中一個(gè)緩存單元(cache line哥纫,也可以翻譯成緩存行),可參考下圖示意痴奏。
緩存單元因其一次必須操作連續(xù)的8Byte的數(shù)據(jù)蛀骇,但是我們不希望類似下面這樣的情況,如兩個(gè)相鄰的整型(4Byte)數(shù)據(jù)會(huì)同時(shí)被多個(gè)CPU核心進(jìn)行頻繁修改读拆,而其都在一個(gè)緩存單元內(nèi)擅憔,其每次修改都會(huì)觸發(fā)我們后面講的核心的緩存到內(nèi)存的同步問題。
我們先看看具體讀寫命中和未命中的情況:
1. 緩存沒有命中的情況:
a). 對(duì)于單核心的讀檐晕,讀操作會(huì)先檢查緩存暑诸,在緩存中沒有數(shù)據(jù)時(shí)會(huì)載入數(shù)據(jù)到緩存(cache line fill)中蚌讼。
b).?對(duì)于單核心的寫,其同讀操作个榕,會(huì)先檢查緩存篡石,在緩存中沒有數(shù)據(jù)時(shí)會(huì)載入數(shù)據(jù)到緩存中,然后執(zhí)行寫操作西采,這里寫操作只是簡單的寫了載入過來的緩存凰萨,并不同步到內(nèi)存(這里需要注意,按照Intel的開發(fā)文檔械馆,老的Pentium默認(rèn)的情況是在緩存miss后寫操作直接寫內(nèi)存胖眷,而不是載入數(shù)據(jù)到緩存后寫緩存)。
2. 緩存命中的情況:
a).?如果讀命中(cache hit)霹崎,則直接使用數(shù)據(jù)珊搀;
b).?如果這里是寫操命(write hit)時(shí)則也是直接操作緩存,而不主動(dòng)同步到內(nèi)存仿畸。
我們也看看CPU的緩存的使用流程:
1. CPU的前端解析L1命令緩存中的指令進(jìn)行預(yù)測(cè)和亂序執(zhí)行等
2. 通過這些指令食棕,計(jì)算單元具體處理從L1數(shù)據(jù)緩存到寄存器中的數(shù)據(jù)的計(jì)算
3. 將計(jì)算的結(jié)果更新到L1數(shù)據(jù)緩存,若要同步緩存中的數(shù)據(jù)到內(nèi)存错沽,則通過硬件實(shí)現(xiàn)的寫緩存邏輯(write buffers)可靠地異步刷新數(shù)據(jù)到系統(tǒng)總線及內(nèi)存(可理解為通過一個(gè)消息隊(duì)列寫)簿晓。
這里可以看參考下圖所示。
這里則是整個(gè)單核心的的流程憔儿,我們注意到,CPU通過緩存提高性能的一個(gè)關(guān)鍵要點(diǎn)是在寫的情況下只寫緩存放可,不同步緩存數(shù)據(jù)到內(nèi)存谒臼。
當(dāng)前版本的多核共享緩存的MESI協(xié)議
而當(dāng)上文所說在多核心時(shí)訪問緩存的時(shí)候,就會(huì)存在數(shù)據(jù)不同步的問題:
這里有一個(gè)在多核環(huán)境下的典型場(chǎng)景:某個(gè)核心Core1把數(shù)據(jù)A從0改成1耀里,Core1把數(shù)據(jù)A存在自己的L1緩存中蜈缤,這時(shí)剛好Core2的L1緩存也緩存了數(shù)據(jù)A,但其值仍然為0冯挎,若這時(shí)Core2對(duì)數(shù)據(jù)A進(jìn)行操作底哥,就是操作了過期的數(shù)據(jù)A,如表1-3所示房官。
為了解決這一問題趾徽,人們提出了MESI協(xié)議,它是一種緩存一致性協(xié)議(cache cohere protocol)翰守,把緩存單元(cache line)的狀態(tài)分為:修改過(M孵奶,Modified)、獨(dú)占(E蜡峰,Exclusive)了袁、共享(S朗恳,Shared)、無效(I早像,Invalid)僻肖,并通過這些狀態(tài)來控制數(shù)據(jù)的寫和同步。
MESI協(xié)議是處理器設(shè)計(jì)時(shí)內(nèi)部支持的卢鹦,通過標(biāo)志位及版本號(hào)來標(biāo)記緩存單元(cache line)臀脏,如在Intel在2017年的手冊(cè)中MESI的狀態(tài)表中描述的,每個(gè)緩存單元(64bit)各自維護(hù)兩個(gè)flag的標(biāo)記位來記錄MESI的協(xié)議等的狀態(tài)信息冀自,而其關(guān)系如表下所示揉稚,表中的“去系統(tǒng)總線”的意思是開始異步寫內(nèi)存數(shù)據(jù)。
MESI協(xié)議的狀態(tài)轉(zhuǎn)換
我們把MESI協(xié)議的變換關(guān)系總結(jié)為表:
為了更清晰描述熬粗,我們?cè)谙旅娈嫵稣w的狀態(tài)圖搀玖,描述M E S I 之間的轉(zhuǎn)換關(guān)系,主要關(guān)注狀態(tài)的變更驻呐。
我們可以認(rèn)為MESI協(xié)議的文字描述如下:
狀態(tài)從Invalid開始灌诅,Read Miss 變成 Exclusive ,Write Miss 變成Modified含末,當(dāng)其它核心有數(shù)據(jù)時(shí)Read Miss 變成 Shared猜拾。
在Exclusive下的讀緩存,不會(huì)改變狀態(tài)佣盒,寫緩存會(huì)使自身狀態(tài)變?yōu)镸odified挎袜,當(dāng)偵測(cè)到其它核心上的當(dāng)前緩存的地址的讀操作,狀態(tài)會(huì)變成Shared肥惭,偵測(cè)到其它核心上的當(dāng)前緩存的地址的寫操作盯仪,狀態(tài)會(huì)變成Invalid。
在Modified下的讀緩存蜜葱,不會(huì)改變狀態(tài)全景,當(dāng)偵測(cè)到其它核心上的當(dāng)前緩存的地址的讀操作,狀態(tài)會(huì)變成Shared牵囤,偵測(cè)到其它核心上的當(dāng)前緩存的地址的寫操作爸黄,狀態(tài)會(huì)變成Invalid。
在Shared下的讀緩存奔浅,不會(huì)改變狀態(tài),寫緩存會(huì)使自身狀態(tài)變?yōu)镸odified诗良,當(dāng)偵測(cè)到其它核心上的當(dāng)前緩存的地址的讀操作汹桦,不會(huì)改變狀態(tài),偵測(cè)到其它核心上的當(dāng)前緩存的地址的寫操作鉴裹,狀態(tài)會(huì)變成Invalid舞骆。
MESI協(xié)議的舉例
看了上面的流程圖后钥弯,我們?cè)購囊粋€(gè)例子來看看MESI協(xié)議的實(shí)際操作,以Modified這個(gè)狀態(tài)為例督禽,現(xiàn)在多核心CPU的實(shí)現(xiàn)是:當(dāng)一個(gè)核心對(duì)一個(gè)緩存單元的數(shù)據(jù)進(jìn)行修改脆霎,使?fàn)顟B(tài)變?yōu)镸odified,這時(shí)當(dāng)其他核心也要操作此緩存單元對(duì)應(yīng)的數(shù)據(jù)地址時(shí)狈惫,當(dāng)前核心會(huì)向打算使用此數(shù)據(jù)的核心發(fā)送信號(hào)睛蛛,通知其改變緩存單元的狀態(tài),并且會(huì)觸發(fā)一次異步的內(nèi)存回寫胧谈,同時(shí)把修改過的數(shù)據(jù)直接傳送給要操作此數(shù)據(jù)的核心忆肾。這時(shí)如果對(duì)方是讀操作,則自己的狀態(tài)變?yōu)镾hared菱肖,對(duì)方的狀態(tài)是Shared客冈;如果對(duì)方是寫操作,則自己的狀態(tài)變?yōu)镮nvalid稳强,對(duì)方的狀態(tài)是Modified场仲。如下兩表。
而如果當(dāng)前核心的一個(gè)緩存單元的狀態(tài)是S退疫,則在偵測(cè)到其他核心寫緩存單元對(duì)應(yīng)的數(shù)據(jù)時(shí)渠缕,會(huì)使此緩存單元的狀態(tài)變?yōu)镮;如果當(dāng)前核心要再次操作之前緩存單元映射的內(nèi)存地址的數(shù)據(jù)蹄咖,則會(huì)再次執(zhí)行另一次緩存載入的操作褐健。如下兩表。
MESI協(xié)議的其它討論
但是AMD的實(shí)現(xiàn)細(xì)節(jié)和INTEL略有不同澜汤,如下圖所示是AMD的MOESI的一個(gè)狀態(tài)變更圖(2013的文檔)蚜迅,它和Intel一樣,也是通過偵測(cè)其他核心對(duì)內(nèi)存的操作傾向來更新緩存單元的狀態(tài)俊抵,并通知其他核心谁不。這里AMD多加了個(gè)Owner的狀態(tài),該狀態(tài)是Modified的升級(jí)徽诲,唯一不同的是允許在其他核心中有Shared狀態(tài)刹帕,而Modified是獨(dú)占狀態(tài)(不允許其它核心有Shared的狀態(tài))。
另外看一些之前的文檔表示Intel根據(jù)MESI拓展出了MESIF協(xié)議谎替,增加了一個(gè)Share的中間狀態(tài)F(Forward)偷溺,表示在此狀態(tài)時(shí)數(shù)據(jù)可以再被傳給其他核心,但現(xiàn)在Intel文檔中只有MESI了钱贯,應(yīng)該是已經(jīng)不再使用了挫掏。
CPU對(duì)內(nèi)存的分類
其實(shí)處理器還對(duì)內(nèi)存進(jìn)行了策略分類,上面介紹的是在默認(rèn)的內(nèi)存類型下的情況(Write Back),如上所述的MESI協(xié)議結(jié)合這個(gè)內(nèi)存類型后秩命,基本可以解決CPU使用的絕大部分場(chǎng)景尉共。
但是CPU在某些使用場(chǎng)景下褒傅,對(duì)緩存和內(nèi)存的一致性有不同程度的強(qiáng)需求,因此袄友,CPU廠商針對(duì)CPU的使用場(chǎng)景設(shè)計(jì)了不同的內(nèi)存類型殿托,比如從不使用緩存,到只有讀使用緩存剧蚣,再到讀寫都使用緩存(Write Back)等各種類型支竹。
這些類型對(duì)我們參看分布式系統(tǒng)中遇到的問題,應(yīng)該還是有很多借鑒意義的券敌,而且有這些內(nèi)存類型的緩存才是完整的一個(gè)緩存系統(tǒng)唾戚,所有也希望大家能了解一下這些,下面按Intel的文檔列出分類:
1.?UC:Strong Uncacheable不可緩存待诅,不可預(yù)測(cè)讀(speculative read)叹坦,分類位UC的內(nèi)存讀寫都不會(huì)被緩存,這里主要對(duì)應(yīng)有內(nèi)存映射的IO設(shè)備的內(nèi)存
a).?AMD對(duì)應(yīng)的名稱:Uncacheable (UC)
2.?UC-:Uncacheable卑雁,不可緩存募书,不可預(yù)測(cè)讀,同UC 测蹲,不過類型被可變?yōu)閃C
a).?AMD名稱:近似Cache Disable (CD)
3.?WC:Write Combining莹捡,不可緩存,可預(yù)測(cè)讀扣甲,同UC-篮赢,但就是可以緩存多個(gè)寫請(qǐng)求后批量提交。
a).?在AMD對(duì)應(yīng)的名稱:同名琉挖,同時(shí)對(duì)應(yīng)AMD的Uncacheable (UC)
b).?在AMD還有一個(gè)WC+?Write Combining plus的類型启泣,這個(gè)對(duì)應(yīng)AMD的CacheDisable (CD)
4.?WT :Write-through 讀操作可緩存,可預(yù)測(cè)讀示辈,可緩存多個(gè)寫請(qǐng)求后批量提交寥茫。但是寫緩存miss時(shí)或緩存單元狀態(tài)位無效時(shí)不刷新寫緩存,直接寫內(nèi)存矾麻;若寫操作能命中緩存時(shí)纱耻,在寫緩存的同時(shí)也寫內(nèi)存(through to)。
a).?在AMD對(duì)應(yīng)的名稱:同名
5.?WB :Write-back默認(rèn)模式险耀,讀寫操作可緩存弄喘,可預(yù)測(cè)讀,可緩存多個(gè)寫請(qǐng)求后批量提交甩牺。寫操作寫緩存后不主動(dòng)提交到內(nèi)存蘑志,當(dāng)回寫操作發(fā)生時(shí)(write back)才把數(shù)據(jù)寫回內(nèi)存。回寫操作發(fā)生的條件是緩存滿后新分配內(nèi)存卖漫,寫舊的緩存單元到內(nèi)存,或MESI在同步數(shù)據(jù)時(shí)赠群。
這個(gè)模式適用于絕大多數(shù)的系統(tǒng)和應(yīng)用程序羊始。
a).?在AMD對(duì)應(yīng)的名稱:同名
6.?WP :Write protected讀操作可緩存,可預(yù)測(cè)讀查描。但是寫操作直接寫內(nèi)存(propagated to)突委,同時(shí)使所有核心的緩存單元變成失效狀態(tài)。
a).?在AMD對(duì)應(yīng)的名稱:同名
對(duì)于這些類型冬三,我們可以參考下面表格來對(duì)比他們的相同和不同匀油。
這里AMD文檔上的一些技術(shù)細(xì)節(jié)和Intel不完全一樣,不過比較這兩個(gè)的區(qū)別現(xiàn)在不是本文重點(diǎn)勾笆,就不詳細(xì)羅列了敌蚜。
處理器的MESI協(xié)議加上這些內(nèi)存類型,就可以按照人們流行的2/8原則解決緩存問題了:80%的情況由默認(rèn)內(nèi)存類型解決窝爪,雖說這個(gè)20%也不簡單弛车,而20%的情況由定義的另外80%的內(nèi)存類型解決。
簡單引申到系統(tǒng)的緩存架構(gòu)及討論
上面主要描述了CPU的緩存架構(gòu)蒲每,CPU需要通過定義內(nèi)存類型纷跛,以及一致性協(xié)議來解決其遇到的多核心下的性能和一致性等問題。
其實(shí)解決多個(gè)核心間的協(xié)同工作邀杏,這一點(diǎn)也和我們?cè)谙到y(tǒng)緩存架構(gòu)上要面對(duì)的一些問題相似贫奠,如緩存架構(gòu)的高并發(fā),高可用望蜡,可伸縮等這些唤崭。
我們認(rèn)為,CPU的寄存器和CPU周期同步其實(shí)也可以理解為是運(yùn)算單元一部分泣特,而L1緩存浩姥,則可認(rèn)為是分布式節(jié)點(diǎn)中的本地內(nèi)存,L2和L3緩存則可以認(rèn)為是共用的Redis這樣的通用緩存状您,內(nèi)存則可以認(rèn)為是數(shù)據(jù)庫與Elasticsearch這些真正的數(shù)據(jù)源勒叠。如表.
參照CPU的設(shè)計(jì)思路,其實(shí)系統(tǒng)上最理想的狀態(tài)是:我們也大量使用分布式節(jié)點(diǎn)的內(nèi)存做緩存膏孟,或更多依賴本地的內(nèi)存進(jìn)行一些計(jì)算眯分,但是這里也有一些問題和挑戰(zhàn):
第一個(gè)就是持久性問題,如果使用緩存的話柒桑,如何解決數(shù)據(jù)的持久性問題弊决,這個(gè)一般需要直接訪問持久化層,如數(shù)據(jù)庫,或消息隊(duì)列飘诗,它們返回成功就認(rèn)為成功与倡。但在一些高性能要求的環(huán)境下,也可以通過主從強(qiáng)一致協(xié)議來完成昆稿,就是寫事務(wù)由主開始纺座,主發(fā)送事務(wù)給從,所有的從都返回收到數(shù)據(jù)給主溉潭,然后主返回成功净响,而在這個(gè)過程中都是內(nèi)存操作,所有的主從通過異步寫數(shù)據(jù)來保證同步喳瓣,如下圖馋贤。
再一個(gè)就是同CPU多核間的臟數(shù)據(jù)問題,這個(gè)可以仍然把緩存分成不同大小的緩存塊畏陕,然后也參考MESI協(xié)議給每個(gè)緩存的數(shù)據(jù)體包裝一層配乓,標(biāo)記一個(gè)狀態(tài)位,以及版本號(hào)惠毁,思路還是多利用Client的內(nèi)存進(jìn)行計(jì)算扰付,使用外部的內(nèi)存進(jìn)行同步。
而緩存的高并發(fā)需求仁讨,也可以看作純網(wǎng)絡(luò)I/O的問題羽莺。我們?cè)?jīng)做過測(cè)試,MySQL可以在命中內(nèi)存索引的情況下達(dá)到10萬每秒的QPS洞豁,而Redis大致也是同樣的表現(xiàn)盐固。
其它的一些提升性能的辦法如在Scaling Memcache at
Facebook的論文中提到:對(duì)所有緩存的依賴進(jìn)行分析,然后把所有沒有依賴關(guān)系的緩存訪問變成并行執(zhí)行丈挟,把有依賴關(guān)系的保留串行執(zhí)行刁卜。比如要獲取一個(gè)商品的信息,同時(shí)獲取商品的類目曙咽、城市蛔趴、門店、優(yōu)惠卷等信息例朱,對(duì)這些緩存信息可以進(jìn)行并行訪問孝情,而由于商品的類型不同,可能具體的字段也不同洒嗤,所以只能串行獲得商品的類型箫荡,這樣可遞歸生成一個(gè)緩存的查詢樹,根據(jù)這個(gè)查詢樹來訪問緩存。如圖。
緩存做可伸縮方案時(shí)需要修改其分片策略,比如Hash從mod 5變?yōu)閙od 10時(shí)需要一個(gè)對(duì)應(yīng)的策略栋盹,有些類似于Redis的Hash擴(kuò)容绞灼,不過變成了在分布式環(huán)境下擴(kuò)容利术,步驟如下。
(1)先分配mod10的主片和從片的空間低矮。
(2)標(biāo)記當(dāng)前的數(shù)據(jù)版本號(hào)氯哮,開始雙寫,同時(shí)寫舊的主片和新的主片商佛。
(3)從標(biāo)記的數(shù)據(jù)版本號(hào)向前異步地遷移數(shù)據(jù)。
(4)在數(shù)據(jù)遷移完成姆打,切換讀到新的片良姆,隨后關(guān)閉舊片的寫入。
(5)遷移完成幔戏,可以刪除舊片玛追。
在擴(kuò)容時(shí)同樣可以參照REIDS集群,預(yù)置緩存槽闲延,然后分配緩存槽給對(duì)應(yīng)的實(shí)例痊剖。但是一致性Hash認(rèn)為存在一些問題,比如會(huì)出現(xiàn)熱點(diǎn)垒玲,又如大量的訪問只在其中一部分Hash段上出現(xiàn)÷侥伲現(xiàn)在,Redis的集群用配置緩存槽可以解決這些問題合愈。
另外叮贩,F(xiàn)acebook的一個(gè)模型是通過MySQL的數(shù)據(jù)復(fù)制同步兩個(gè)大的數(shù)據(jù)中心,并同時(shí)維護(hù)兩個(gè)本地的緩存池的
對(duì)于更新緩存數(shù)據(jù)佛析,F(xiàn)acebook也提出一個(gè)很好的緩存模式益老,比如上面提到的MySQL等主流數(shù)據(jù)工具的事務(wù)成功都不是實(shí)際的數(shù)據(jù)持久化成功,而是在寫日志成功時(shí)就認(rèn)為是事務(wù)成功寸莫。所以捺萌,我們也可以根據(jù)MySQL的事務(wù)日志來更新緩存的信息,這樣可以更好地解決緩存失效的問題膘茎。
這里我們拋磚引玉一的討論了一下緩存系統(tǒng)的架構(gòu)設(shè)計(jì)桃纯,也希望介紹的CPU的緩存的架構(gòu)的這些內(nèi)容能對(duì)大家在設(shè)計(jì)和使用緩存中有所幫助,后續(xù)我們也希望有機(jī)會(huì)做出我們新的緩存中間件披坏。