GFS 經(jīng)典設(shè)計(jì),給了我們哪些架構(gòu)啟示?
工程架構(gòu),Google乃先驅(qū)。其GFS(Google File System)有哪些優(yōu)秀的架構(gòu)設(shè)計(jì)點(diǎn),值得我們學(xué)習(xí)借鑒呢?

GFS是什么?
Google早期研發(fā)的分布式文件系統(tǒng)。
GFS的設(shè)計(jì)目標(biāo)是什么?
主要有四個(gè)目標(biāo):
- 高可用(availability);
- 高可靠(reliability);
- 高性能(performance);
- 可擴(kuò)展(scalability);
GFS對(duì)外提供什么接口?
文件創(chuàng)建,刪除,打開,關(guān)閉,讀,寫,快照。
畫外音:
- 除了快照,接口和單機(jī)文件系統(tǒng)差不多。
- 快照其實(shí)是快速文件目錄樹的拷貝,并不是所有文件的快照。
- GFS能夠成為分布式架構(gòu)的經(jīng)典案例,原因之一,就是接口簡單,但反映的架構(gòu)理念不簡單。
GFS的系統(tǒng)架構(gòu)如何?
系統(tǒng)里只有文件客戶端,主服務(wù)器,存儲(chǔ)服務(wù)器三個(gè)角色。

如上圖:
- 客戶端(GFS client),是以庫的形式提供的,提供的就是對(duì)外要用的接口;
- 主服務(wù)器(GFS master),是單點(diǎn),存儲(chǔ)文件信息,目錄信息,文件服務(wù)器信息,那個(gè)文件存在哪些文件服務(wù)器上等元數(shù)據(jù);
- 存儲(chǔ)服務(wù)器(GFS chunk-server),是集群,存儲(chǔ)文件;
畫外音:角色簡單,但反映的架構(gòu)理念不簡單。
為什么要設(shè)計(jì)單點(diǎn)master?
單點(diǎn)master意味著有一個(gè)節(jié)點(diǎn)可以避免分布式鎖,可以擁有全局視野,能夠統(tǒng)一調(diào)度與監(jiān)控,系統(tǒng)整體復(fù)雜度降低很多。
畫外音:鎖可以降級(jí)成本地鎖,分布式調(diào)度可以降級(jí)為單點(diǎn)調(diào)度。
更具體的:
- master擁有所有文件目錄結(jié)構(gòu),要操作某個(gè)文件,必須獲得相應(yīng)的鎖;
畫外音:一般情況下,不會(huì)對(duì)同一個(gè)網(wǎng)頁進(jìn)行并發(fā)寫操作,應(yīng)用場(chǎng)景決定鎖沖突其實(shí)不大;
- master擁有全局視野,能夠避免死鎖;
- master知道chunk-server的信息,能夠很容易的做chunk-server監(jiān)控,負(fù)載均衡;
- master知道所有文件的副本分布信息,能夠很容易的做文件大小的負(fù)載均衡;
畫外音:負(fù)載均衡分為請(qǐng)求量的均衡,文件存儲(chǔ)的容量均衡。
GFS的高可用是怎么保證的?
高可用又分為服務(wù)高可用,文件存儲(chǔ)高可用,均通過“冗余+自動(dòng)故障轉(zhuǎn)移”的思路來實(shí)現(xiàn)。
(1) master高可用:冗余了一臺(tái)影子master,平時(shí)不工作,master掛了工作,以保證master的高可用;
畫外音:master資源利用率只有50%。
(2) chunk-server高可用:本身是集群,冗余服務(wù);
畫外音:當(dāng)有chunk-server掛掉,master能檢測(cè)到,并且知道哪些文件存儲(chǔ)在chunk-server上,就可以啟動(dòng)新的實(shí)例,并復(fù)制相關(guān)文件。
(3) 文件存儲(chǔ)高可用:每一份文件會(huì)存三份,冗余文件;
GFS的高性能是怎么保證的?
多個(gè)chunk-server可以通過線性擴(kuò)展提升處理能力和存儲(chǔ)空間,GFS的潛在瓶頸是單點(diǎn)master,所以GFS要想達(dá)到超高性能,主要架構(gòu)優(yōu)化思路在于,“提升master性能,減少與master交互”。
- 只存儲(chǔ)元數(shù)據(jù),不存儲(chǔ)文件數(shù)據(jù),不讓磁盤容量成為master瓶頸;
- 元數(shù)據(jù)會(huì)存儲(chǔ)在磁盤和內(nèi)存里,不讓磁盤IO成為master瓶頸;
- 元數(shù)據(jù)大小內(nèi)存完全能裝得下,不讓內(nèi)存容量成為master瓶頸;
- 所有數(shù)據(jù)流,數(shù)據(jù)緩存,都不走master,不讓帶寬成為master瓶頸;
- 元數(shù)據(jù)可以緩存在客戶端,每次從客戶端本地緩存訪問元數(shù)據(jù),只有元數(shù)據(jù)不準(zhǔn)確的時(shí)候,才會(huì)訪問master,不讓CPU成為成為master瓶頸;
當(dāng)然,chunk-server雖然有多個(gè),也會(huì)通過一些手段提升chunk-server的性能,例如:
- 文件塊使用64M,避免太多碎片降低性能;
- 使用追加寫,而不是隨機(jī)寫,提升性能;
- 使用TCP長連接,提升性能;
GFS如何保證系統(tǒng)可靠性?
保證元數(shù)據(jù)與文件數(shù)據(jù)的可靠性,GFS使用了很多非常經(jīng)典的手段。
(1) 元數(shù)據(jù)的變更,會(huì)先寫日志,以確保不會(huì)丟失;
畫外音:日志也會(huì)冗余,具備高可用。
(2) master會(huì)輪詢探測(cè)chunk-server的存活性,保證有chunk-server失效時(shí),chunk-server的狀態(tài)是準(zhǔn)確的;
畫外音:文件會(huì)存多份,短時(shí)間內(nèi)chunk-server掛掉是不影響的。
(3) 元數(shù)據(jù)的修改是原子的,由master控制,master必須保證元數(shù)據(jù)修改的順序性;
(4) 文件的正確性,通過checksum保證;
(5) 監(jiān)控,快速發(fā)現(xiàn)問題;
讀操作的核心流程?
文件讀取是最高頻的操作。
- client讀本地緩存,看文件在哪些chunk-server上;
- 如果client本地緩存miss,詢問master文件所在位置,并更新本地緩存;
- 從一個(gè)chunk-server里讀文件,如果讀取到,就返回;
寫操作的核心流程?
寫操作會(huì)復(fù)雜很多。
為了保證數(shù)據(jù)高可用,數(shù)據(jù)必須在多個(gè)chunk-server上寫入多個(gè)副本,首先要解決的問題是,如何保證多個(gè)chunk-server上的數(shù)據(jù)是一致的呢?
想想一個(gè)MySQL集群的多個(gè)MySQL實(shí)例,是如何保證多個(gè)實(shí)例的數(shù)據(jù)一致性的。bingo!確定一個(gè)主實(shí)例,串行化所有寫操作,然后在其他實(shí)例重放相同的操作序列,以保證多個(gè)實(shí)例數(shù)據(jù)的一致性。
GFS也采用了類似的策略,一個(gè)文件冗余3份,存在3個(gè)chunk-server上,如下圖步驟1-7:

(1) client訪問master,要發(fā)起文件寫操作;
畫外音:假設(shè)client本地緩存未生效;
(2) master返回?cái)?shù)據(jù)存儲(chǔ)在ABC三個(gè)實(shí)例上,并且告之其中一個(gè)實(shí)例是主chunk-server;
(3) client將數(shù)據(jù)流傳遞給所有chunk-server;
(4) client將控制流產(chǎn)地給主chunk-server;
(5) 主chunk-server進(jìn)行本地操作串行化,并將序列化后的命令發(fā)送給其他chunk-server;
(6) 其他chunk-server按照相同的控制流對(duì)數(shù)據(jù)進(jìn)行操作,并將結(jié)果告訴主chunk-server;
(7) 主chunk-server收到其他所有chunk-server的成果執(zhí)行結(jié)果后,將結(jié)果返回client;
畫外音:MySQL的主庫是寫瓶頸,GFS不會(huì)出現(xiàn)這樣的問題,每個(gè)文件的主chunk-server是不同的,所以每個(gè)實(shí)例的寫請(qǐng)求也是均衡的。
這里需要說明的是,GFS對(duì)于寫操作,執(zhí)行的是最保守的策略,必須所有chunk寫成功,才會(huì)返回client寫成功(寫吞吐會(huì)降低);這樣的好處是,讀操作只要一個(gè)chunk讀取成功,就能返回讀成功(讀吞吐會(huì)提升)。
畫外音:這也符合R+W>N的定理,N=3份副本,W=3寫3個(gè)副本才算成功,R=1讀1個(gè)副本就算成功。R+W>N定理未來再詳述。
之所以這么設(shè)計(jì),和文件操作“讀多寫少”的特性有關(guān)的,Google抓取的網(wǎng)頁,更新較少,讀取較多,這也是一個(gè)設(shè)計(jì)折衷的典型。
畫外音:任何脫離業(yè)務(wù)的架構(gòu)設(shè)計(jì)都是耍流氓。
除此之外,這里還有一個(gè)“數(shù)據(jù)流與控制流分離”的設(shè)計(jì)準(zhǔn)則:
- 控制流數(shù)據(jù)量小,client直接與主chunk-server交互;
- 數(shù)據(jù)流數(shù)據(jù)量大,client選擇“最近的路徑”發(fā)送數(shù)據(jù);
畫外音:所謂“最近”,可以通過IP的相似度計(jì)算得到。
總結(jié)
GFS的架構(gòu),體現(xiàn)了很多經(jīng)典的設(shè)計(jì)實(shí)踐:
- 簡化系統(tǒng)角色,單點(diǎn)master降低系統(tǒng)復(fù)雜度;
- 不管是文件還是服務(wù),均通過“冗余+故障自動(dòng)轉(zhuǎn)移”保證高可用;
- 由于存在單點(diǎn)master,GFS將“降低與單點(diǎn)master的交互”作為性能優(yōu)化核心;
- 通過寫日志,原子修改,checksum,快速監(jiān)控快速恢復(fù)等方式保證可靠性與完整性;
- 通過串行化保證多個(gè)副本數(shù)據(jù)的一致性;
- 控制流與數(shù)據(jù)流分離,提高性能;
知其然,知其所以然。
思路比結(jié)論更重要。

























