深度拆解:從分布式文件系統(tǒng)設(shè)計(jì)到HDFS對比與面試指南)
這次我們來看 GFSGoogle File System也就是 Google 在 2003 年 SOSP 會議上公開的分布式文件系統(tǒng)設(shè)計(jì)。它是整個大數(shù)據(jù)生態(tài)繞不開的祖師爺級系統(tǒng)HDFS 的塊、副本、NameNode/DataNode 架構(gòu)幾乎都能在 GFS 論文里找到原型。如果你在準(zhǔn)備系統(tǒng)設(shè)計(jì)面試、做分布式存儲選型或者單純想把“分布式文件系統(tǒng)到底怎么設(shè)計(jì)”這件事搞清楚這篇應(yīng)該能省你不少時(shí)間。文章不會只梳理概念而是按系統(tǒng)設(shè)計(jì)的方法拆解先給設(shè)計(jì)指標(biāo)再拆架構(gòu)組件然后走讀寫流程和一致性模型最后落到故障恢復(fù)、與 HDFS 的對比、面試回答套路這幾個方向。整個過程保持工程視角不堆名詞。1. 核心能力速覽先給一張 GFS 的總體認(rèn)知表方便后續(xù)閱讀時(shí)對號入座。下面這些參數(shù)來自 GFS 發(fā)表于 2003 年的論文數(shù)據(jù)是 Google 當(dāng)時(shí)的集群環(huán)境和負(fù)載特征注意區(qū)分“論文設(shè)計(jì)目標(biāo)”和“當(dāng)前硬件條件下的實(shí)測結(jié)論”。能力項(xiàng)說明系統(tǒng)定位大規(guī)模分布式文件系統(tǒng)面向海量數(shù)據(jù)順序讀、追加寫場景發(fā)布時(shí)間2003 年 SOSP 論文公開核心解決場景MapReduce、BigTable 等海量數(shù)據(jù)批處理任務(wù)塊Chunk大小64MB遠(yuǎn)大于傳統(tǒng)文件系統(tǒng)的 4KB 級塊默認(rèn)副本數(shù)3 個可通過配置調(diào)整節(jié)點(diǎn)角色Master、ChunkServer、Client一致性模型弱一致性追加寫保證“至少一次”可能出現(xiàn)重復(fù)單點(diǎn)問題Master 是單點(diǎn)靠操作日志 Checkpoint 恢復(fù)故障恢復(fù)ChunkServer 心跳超時(shí)后重新復(fù)制副本寫入模型數(shù)據(jù)流與控制流分離主副本鏈?zhǔn)睫D(zhuǎn)發(fā)與 HDFS 關(guān)系HDFS 是 GFS 設(shè)計(jì)的開源簡化版本適合場景超大文件、追加寫、批量讀、粗粒度容錯不適合場景小文件密集、低延遲隨機(jī)寫、強(qiáng)一致事務(wù)從這張表能直接讀出 GFS 的哲學(xué)它不為通用文件系統(tǒng)設(shè)計(jì)而是為搜索引擎爬取數(shù)據(jù)、網(wǎng)頁索引、MapReduce 中間結(jié)果這種“一次寫多次讀、按批處理”的負(fù)載設(shè)計(jì)。所有核心決策都是從這套負(fù)載特征推出來的。2. 適用場景與使用邊界學(xué)習(xí)系統(tǒng)設(shè)計(jì)最難的不是記住組件而是理解“為什么這樣設(shè)計(jì)”。GFS 的整個設(shè)計(jì)幾乎都是圍繞它的目標(biāo)負(fù)載展開的。2.1 適合解決什么問題GFS 要解決的核心問題有三類。第一海量數(shù)據(jù)存儲。Google 當(dāng)時(shí)要存儲全網(wǎng)的網(wǎng)頁快照、URL 列表、反向索引等數(shù)據(jù)單臺服務(wù)器的磁盤放不下必須橫向擴(kuò)展到上千臺機(jī)器。第二廉價(jià)硬件上的高可靠性。Google 當(dāng)時(shí)用的是大量普通服務(wù)器磁盤損壞、節(jié)點(diǎn)宕機(jī)是常態(tài)。GFS 必須把故障當(dāng)成正常狀態(tài)來對待而不是異常。第三大文件的高吞吐。搜索引擎的索引文件動輒幾個 GB 甚至更大文件系統(tǒng)的吞吐能力比隨機(jī)訪問延遲更重要。2.2 為什么不適合通用場景反過來看GFS 的很多設(shè)計(jì)放在通用文件系統(tǒng)里是反常識的。64MB 的塊大小對小文件極不友好。一個 1KB 的文件也至少要占一個 Chunk 的元數(shù)據(jù)位置上億個小文件會直接壓爆 Master 內(nèi)存。弱一致模型不適合需要強(qiáng)一致性的數(shù)據(jù)庫、交易類應(yīng)用。隨機(jī)寫效率差整個設(shè)計(jì)明顯偏向追加寫。POSIX 兼容性幾乎沒有普通 Linux 程序沒法直接把 GFS 掛載當(dāng)作 NFS 使用。所以在系統(tǒng)設(shè)計(jì)面試?yán)锶绻}目是“設(shè)計(jì)一個分布式文件系統(tǒng)”第一步不是抄 GFS而是先定義你的負(fù)載是什么。如果是大量小文件、需要 POSIX 兼容那么 GFS 不是最優(yōu)答案可能要往 JuiceFS、GlusterFS、CephFS 的方向思考。3. GFS 整體架構(gòu)與核心組件GFS 集群由三類角色組成Master、ChunkServer、Client。3.1 Master元數(shù)據(jù)管理中心Master 是集群的“大腦”但它不存文件數(shù)據(jù)只保存三類元數(shù)據(jù)文件命名空間文件名到 Chunk 索引的映射。文件到 Chunk 的映射一個文件由哪些 Chunk 組成。Chunk 副本的位置信息每個 Chunk 存放在哪些 ChunkServer 上。前兩類元數(shù)據(jù)會持久化到操作日志Operation Log中第三類副本位置信息不需要持久化Master 啟動后通過 ChunkServer 心跳上報(bào)來構(gòu)建。Master 還負(fù)責(zé)整個集群的調(diào)度Chunk 副本創(chuàng)建、刪除、遷移、復(fù)制以及租約Lease的管理。所有元數(shù)據(jù)操作都需要經(jīng)過 MasterMaster 因此成為整個系統(tǒng)最關(guān)鍵的瓶頸點(diǎn)。從論文數(shù)據(jù)看Master 用 64 字節(jié)左右的元數(shù)據(jù)管理一個 Chunk生產(chǎn)環(huán)境中會進(jìn)一步壓縮。這里不寫死數(shù)字要記住的結(jié)論是GFS 的文件數(shù)量上限受 Master 內(nèi)存大小限制這也是它不適合海量小文件的直接原因。3.2 ChunkServer真正存數(shù)據(jù)的地方ChunkServer 負(fù)責(zé)實(shí)際的數(shù)據(jù)存儲。每個 Chunk 在 ChunkServer 上以普通 Linux 文件的形式存在磁盤可能碎片化但 GFS 不要求 ChunkServer 做復(fù)雜的磁盤管理。每個 Chunk 默認(rèn)保存 3 個副本分布在不同的機(jī)架或機(jī)器上。這樣設(shè)計(jì)有兩個目的一是防止單機(jī)故障導(dǎo)致數(shù)據(jù)丟失二是讀請求可以分散到多個 ChunkServer提升讀取吞吐。ChunkServer 之間會通過心跳把自身狀態(tài)上報(bào)給 Master也處理 Client 發(fā)來的讀寫請求。3.3 Client文件訪問入口Client 是 GFS 對應(yīng)用層暴露的 API 接口提供創(chuàng)建文件、刪除文件、打開文件、讀文件、寫文件等操作。它不是 POSIX 接口而是一套自定義的 GFS API。GFS 的 Client 有一個重要設(shè)計(jì)它會緩存 Chunk 的位置信息。一個 Client 在第一次讀取某個 Chunk 時(shí)向 Master 請求位置之后就在本地緩存不用每次讀都打一次 Master。這樣可以大幅降低 Master 壓力但緩存的副作用是位置信息可能過期所以 Client 需要定期重新請求。3.4 命名空間鎖GFS 的命名空間操作也采用鎖機(jī)制。每個文件或目錄上可以加讀鎖或?qū)戞i。多個操作需要獲取鎖后才能執(zhí)行例如創(chuàng)建文件要在父目錄上持有讀鎖、在目標(biāo)文件名上持有寫鎖。因?yàn)殒i粒度細(xì)GFS 的并發(fā)目錄操作性能比傳統(tǒng)文件系統(tǒng)高得多。這個設(shè)計(jì)后面在面試?yán)锟梢援?dāng)作亮點(diǎn)回答“GFS 如何保證目錄并發(fā)操作安全”。4. GFS 讀寫流程拆解這一部分是系統(tǒng)設(shè)計(jì)面試最容易考的細(xì)節(jié)。光記住“Client 連 Master 拿元數(shù)據(jù)然后連 ChunkServer 讀寫數(shù)據(jù)”不夠要能把每個步驟說清楚。4.1 寫流程普通 WriteGFS 的寫流程可以拆成下面幾步Client 向 Master 請求目標(biāo) Chunk 的持有租約的 ChunkServer 位置。Master 返回主副本 ChunkServer 和其他副本 ChunkServer 的地址。Client 把數(shù)據(jù)推送到離自己最近的副本 ChunkServer數(shù)據(jù)流。收到數(shù)據(jù)的 ChunkServer 把數(shù)據(jù)繼續(xù)推送到鏈路中的下一個副本 ChunkServer依此類推直到所有副本都收到數(shù)據(jù)。所有副本確認(rèn)收到數(shù)據(jù)后Client 向主副本 ChunkServer 發(fā)送寫請求控制流。主副本 ChunkServer 為這次寫分配一個全局唯一的序列號按序?qū)懭氩褜懻埱蟀l(fā)給其他副本 ChunkServer。所有副本完成寫入后主副本向 Client 返回成功響應(yīng)。Client 收到響應(yīng)后如果中間有一步失敗就會重試整個流程。這個流程里有幾個關(guān)鍵點(diǎn)值得展開。關(guān)鍵點(diǎn)一數(shù)據(jù)流與控制流分離??刂坡窂绞?Client - 主副本 - 其他副本數(shù)據(jù)路徑是 Client - 最近的副本 - 鏈?zhǔn)睫D(zhuǎn)發(fā)到其他副本。這樣設(shè)計(jì)的目的很直接數(shù)據(jù)沿著最短路徑傳輸減少跨機(jī)架流量控制路徑則保證寫入順序一致。關(guān)鍵點(diǎn)二主副本的寫入順序。所有并發(fā)寫請求都由主副本分配序列號保證多個 Client 并發(fā)寫同一個 Chunk 時(shí)所有副本以相同順序接收數(shù)據(jù)避免副本間數(shù)據(jù)不一致。關(guān)鍵點(diǎn)三寫入失敗的處理。GFS 的寫入不是原子的。如果一個寫操作在部分副本成功、部分副本失敗GFS 會返回錯誤給應(yīng)用層應(yīng)用層需要自己決定是否重試。這部分體現(xiàn)了 GFS 的設(shè)計(jì)哲學(xué)把復(fù)雜性交給應(yīng)用層而不是隱藏在文件系統(tǒng)內(nèi)部。4.2 追加寫流程Record Append追加寫是 GFS 的重要特性也是面試的高頻考點(diǎn)。MapReduce 這類系統(tǒng)經(jīng)常需要把多個結(jié)果追加到同一個文件如果使用普通 Write多個 Client 并發(fā)寫會導(dǎo)致數(shù)據(jù)交錯不可接受。GFS 的 Record Append 語義如下多個 Client 可以并發(fā)對同一個文件追加數(shù)據(jù)。GFS 保證每條記錄至少被寫入一次at-least-once但不保證每條記錄只寫入一次。如果某次追加在部分副本上成功、部分失敗GFS 會返回錯誤應(yīng)用層需要檢查該區(qū)域是否出現(xiàn)重復(fù)記錄。每條追加的記錄在文件中是原子性的即讀取方不會看到半條記錄。這種“至少一次”模型非常適合 MapReduce 的中間結(jié)果寫入哪怕有重復(fù)記錄應(yīng)用層也能通過唯一標(biāo)識符去重。4.3 讀流程讀流程相對簡單Client 向 Master 發(fā)送讀請求攜帶文件名和偏移量。Master 返回對應(yīng)的 Chunk 句柄和副本位置。Client 選擇一個副本位置通常是最近的緩存到本地。Client 向 ChunkServer 發(fā)送讀請求指定 Chunk 句柄和字節(jié)范圍。ChunkServer 返回?cái)?shù)據(jù)。如果 ChunkServer 返回?cái)?shù)據(jù)校驗(yàn)失敗比如磁盤壞道Client 會換一個副本讀取并把壞副本情況上報(bào)給 Master。5. GFS 一致性模型與故障恢復(fù)GFS 的一致性模型是它最容易被誤讀的部分。很多人都知道 GFS“弱一致”但當(dāng)被問“具體弱在哪里”“和數(shù)據(jù)一致性面試題里的最終一致性有什么區(qū)別”時(shí)往往答不清楚。5.1 一致性定義GFS 論文定義了四種狀態(tài)一致Consistent所有客戶端看到相同的數(shù)據(jù)無論它們訪問的是哪個副本。已定義Defined文件區(qū)域是一致的且客戶端能夠看到寫入操作寫入的完整數(shù)據(jù)。已定義但中間結(jié)果交錯并發(fā)寫交織在一起每條記錄都是完整的但先后順序不確定。不一致Inconsistent不同客戶端可能看到不同的副本內(nèi)容。對于普通寫操作如果成功寫入的區(qū)域是已定義的如果并發(fā)寫區(qū)域是已定義的但數(shù)據(jù)可能交錯如果有部分失敗區(qū)域可能不一致。對于追加寫操作只要追加成功區(qū)域就是已定義的但可能存在重復(fù)記錄。GFS 不處理重復(fù)交給應(yīng)用層判斷。5.2 Master 的故障恢復(fù)Master 單點(diǎn)故障是 GFS 最明顯的弱點(diǎn)。它通過兩個方面緩解操作日志Operation LogMaster 的每次元數(shù)據(jù)操作都會追加到日志中寫日志成功后才返回客戶端成功。Checkpoint當(dāng)操作日志達(dá)到一定大小Master 生成 Checkpoint 快照之后從 Checkpoint 加載狀態(tài)再重放后續(xù)日志。GFS 論文里提到Master 恢復(fù)時(shí)還有影子 MasterShadow Master機(jī)制提供只讀訪問避免恢復(fù)期間整個系統(tǒng)不可用?;謴?fù)時(shí)間取決于日志重放速度但遠(yuǎn)比重新掃描所有 ChunkServer 要快。5.3 ChunkServer 故障與副本恢復(fù)Master 通過周期心跳監(jiān)控 ChunkServer。如果某個 ChunkServer 心跳超時(shí)Master 會將該節(jié)點(diǎn)標(biāo)記為不可用并為它負(fù)責(zé)的 Chunk 在每個副本數(shù)低于閾值的文件上重新創(chuàng)建副本。新副本的創(chuàng)建優(yōu)先從最后一個活副本復(fù)制因?yàn)樽詈笠粋€副本的數(shù)據(jù)往往最新。復(fù)制完成后Master 更新元數(shù)據(jù)中的副本位置信息。5.4 租約機(jī)制租約是 GFS 控制并發(fā)寫順序的核心機(jī)制。主副本 ChunkServer 擁有一個租約租約有效期默認(rèn) 60 秒。租約內(nèi)該 ChunkServer 作為主副本接受寫請求分配寫入順序。租約到期后Master 可以重新分配主副本給其他 ChunkServer。如果主副本宕機(jī)或與 Master 失聯(lián)租約會在超時(shí)后自動到期新的主副本會被重新選舉。租約的核心作用就是解決“主副本掛了誰來做主”的問題。沒有租約兩個 ChunkServer 會同時(shí)認(rèn)為自己有寫權(quán)限數(shù)據(jù)一致性就會出問題。5.5 垃圾回收GFS 的刪除操作不立即釋放空間。刪除文件時(shí)Master 只是把文件名標(biāo)記為隱藏并在操作日志中記錄然后延遲一段時(shí)間通常是 3 天后才真正刪除物理數(shù)據(jù)。這樣做的好處是如果誤刪文件可以快速恢復(fù)也避免了刪除過程中的復(fù)雜狀態(tài)管理。壞處是磁盤空間回收有延遲對于空間緊張的場景不友好。6. 系統(tǒng)設(shè)計(jì)亮點(diǎn)與潛在問題GFS 能在系統(tǒng)設(shè)計(jì)面試?yán)锉环磸?fù)提及是因?yàn)樗w現(xiàn)了大量可復(fù)用的設(shè)計(jì)思想。6.1 值得借鑒的設(shè)計(jì)亮點(diǎn)大塊設(shè)計(jì)降低元數(shù)據(jù)壓力。64MB 的 Chunk 讓文件被切分的數(shù)量大大減少M(fèi)aster 需要維護(hù)的元數(shù)據(jù)項(xiàng)也隨之減少。同時(shí)一個 Chunk 可以在一個 ChunkServer 上連續(xù)存儲有利于順序讀寫。租約避免集中式鎖服務(wù)。GFS 沒有引入 Paxos 或 Raft 來處理 Master 選主和分布式鎖而是用租約把寫控制權(quán)下放到單個 ChunkServer。這讓系統(tǒng)在早期避免了復(fù)雜的分布式共識問題代價(jià)是 Master 成為單點(diǎn)。數(shù)據(jù)流與控制流分離。寫入數(shù)據(jù)沿著復(fù)制鏈傳輸控制流獨(dú)立走另一條路徑。這個設(shè)計(jì)在 HDFS 中也被繼承是理解分布式存儲寫入路徑的重要概念。追加寫模型契合批處理負(fù)載。多個 Consumer 并發(fā)寫入同一個日志文件是 MapReduce 中最常見的寫模式。GFS 為這種模式設(shè)計(jì)的 Record Append 語義比 POSIX 的 write 語義更實(shí)用。寫后校驗(yàn)和保證數(shù)據(jù)完整性。每個 ChunkServer 會為 Chunk 中的每個 64KB 小分塊計(jì)算校驗(yàn)和。讀取時(shí)校驗(yàn)失敗會嘗試其他副本防止靜默數(shù)據(jù)損壞。寫時(shí)復(fù)制快照。GFS 的快照用寫時(shí)復(fù)制Copy-on-Write實(shí)現(xiàn)創(chuàng)建快照時(shí)不需要復(fù)制數(shù)據(jù)只有在修改某個 Chunk 時(shí)才復(fù)制成本極低。6.2 需要避開的坑Master 單點(diǎn)瓶頸。論文時(shí)代的 GFS 沒有真正解決 Master 單點(diǎn)問題主要依賴恢復(fù)機(jī)制而非可用性機(jī)制。后來的 Colossus 才解決了元數(shù)據(jù)水平擴(kuò)展問題。系統(tǒng)設(shè)計(jì)時(shí)如果你的集群規(guī)模超過幾萬臺單 Master 設(shè)計(jì)基本不可行。元數(shù)據(jù)全內(nèi)存。所有元數(shù)據(jù)都放在 Master 內(nèi)存中文件數(shù)量被內(nèi)存上限鎖死。設(shè)計(jì)時(shí)如果預(yù)判小文件數(shù)量巨大要么用內(nèi)存更大的機(jī)器要么引入元數(shù)據(jù)分片。追加寫重復(fù)?!爸辽僖淮巍币馕吨鴶?shù)據(jù)可能重復(fù)寫入這對需要精確一次的流式處理場景不夠友好。應(yīng)用層必須做冪等處理。隨機(jī)寫性能差。GFS 的寫路徑是發(fā)給主副本再鏈?zhǔn)綇?fù)制隨機(jī)寫場景會產(chǎn)生大量隨機(jī) IO性能會很難看。7. 與 HDFS 的對比GFS 論文不開放源碼但 HDFS 在設(shè)計(jì)上大量借鑒了 GFS 的思想理解兩者的差異能幫助你更清楚地看到 GFS 的本質(zhì)。對比項(xiàng)GFSHDFS論文/源碼論文公開代碼未開源開源實(shí)現(xiàn)塊大小64MB默認(rèn) 128MB主節(jié)點(diǎn)MasterNameNode數(shù)據(jù)節(jié)點(diǎn)ChunkServerDataNode寫入模型隨機(jī)寫 追加寫追加為主早期不支持隨機(jī)寫一致性弱一致追加至少一次同 GFS 思路弱一致高可用恢復(fù)機(jī)制 Shadow Master2NN / QJM 高可用方案典型應(yīng)用MapReduce、BigTableMapReduce、Spark、HivePOSIX 兼容否否HDFS 最大的改進(jìn)是引入了高可用方案Active NameNode 和 Standby NameNode 通過 JournalNode 共享編輯日志主節(jié)點(diǎn)故障時(shí)可以進(jìn)行自動切換。而 GFS 論文時(shí)代的 Master 恢復(fù)依賴 Shadow Master不能自動切換為可寫狀態(tài)。另一個差異是 HDFS 早期不支持隨機(jī)寫只支持追加寫。從這個角度看HDFS 對 GFS 的任務(wù)負(fù)載理解得更徹底刪掉不常用的能力保留最核心的批處理路徑。8. 面試與系統(tǒng)設(shè)計(jì)題怎么答GFS 是系統(tǒng)設(shè)計(jì)面試中“分布式文件系統(tǒng)”“分布式存儲”類題目的原型。這里給出一套直接可用的答題框架。8.1 問題設(shè)計(jì)一個分布式文件系統(tǒng)如果面試官讓你設(shè)計(jì)分布式文件系統(tǒng)可以按照下面的順序組織回答。第一步定義需求。先問清楚數(shù)據(jù)規(guī)模、文件大小分布、讀寫比例、一致性要求、容錯要求。GFS 就是先確定了“大文件、順序讀、追加寫、弱一致可接受”這套約束才推導(dǎo)出后續(xù)的所有設(shè)計(jì)。第二步定架構(gòu)。采用 Master-Slave 結(jié)構(gòu)Master 管元數(shù)據(jù)數(shù)據(jù)節(jié)點(diǎn)管數(shù)據(jù)。點(diǎn)出 Master 單點(diǎn)是后續(xù)要解決的問題。第三步拆數(shù)據(jù)單元。設(shè)置大塊64MB 或 128MB三個副本分布在多機(jī)房/多機(jī)架。這一步能體現(xiàn)你理解元數(shù)據(jù)規(guī)模和數(shù)據(jù)可靠性的權(quán)衡。第四步設(shè)計(jì)讀寫流程。寫流程要講數(shù)據(jù)流與控制流分離、主副本鏈?zhǔn)綇?fù)制讀流程要講按副本就近讀取、位置緩存。第五步處理故障。Master 故障用操作日志 Checkpoint 恢復(fù)ChunkServer 故障用副本重復(fù)制主節(jié)點(diǎn)故障可以用租約 新主選舉。第六步說清楚一致性模型。明確系統(tǒng)是弱一致的追加寫至少一次應(yīng)用層需要處理重復(fù)數(shù)據(jù)。8.2 問題為什么 GFS 不采用 POSIX 接口這個問題考察的是“你是否真的理解 GFS 面向批處理的本質(zhì)”。GFS 的目標(biāo)負(fù)載是 MapReduce 和 BigTable它們不需要 POSIX 接口的語義不需要目錄的 POSIX 權(quán)限控制不需要文件鎖不需要 mmap。換成自定義 API 后GFS 可以對 Chunk 做更細(xì)粒度的位置感知和調(diào)度這是 POSIX 接口做不到的。8.3 問題Master 掛了怎么辦這是考系統(tǒng)設(shè)計(jì)基本功的問題。回答分成三部分一是數(shù)據(jù)不丟因?yàn)閿?shù)據(jù)都在 ChunkServer 上Master 只存元數(shù)據(jù)二是元數(shù)據(jù)能恢復(fù)通過操作日志和 Checkpoint 重放三是恢復(fù)期間服務(wù)降級可以用 Shadow Master 提供只讀服務(wù)。引申一步再補(bǔ)一句真正解決單點(diǎn)問題的方案是把 Master 設(shè)計(jì)成主備模式并用共識算法選主或者做元數(shù)據(jù)分片Google 后來在 Colossus 中采用后者。9. 學(xué)習(xí) GFS 常見誤區(qū)與排查思路這里不是運(yùn)維排障而是學(xué)習(xí)路徑上的“排雷”。下表列出大多數(shù)人理解 GFS 時(shí)容易踩的坑以及對應(yīng)的修正方法。誤區(qū)現(xiàn)象錯誤理解正確理解如何驗(yàn)證以為 GFS 支持強(qiáng)一致寫入寫入成功后所有副本立刻相同寫成功只代表主副本接收成功副本間弱一致閱讀論文一致性定義段落以為 GFS 和 HDFS 完全等價(jià)兩者架構(gòu)完全相同核心思想相同HDFS 簡化和演進(jìn)對比論文與 HDFS 文檔以為 Chunk 是“文件分塊后存多份”Chunk 就是文件邏輯分塊Chunk 是獨(dú)立的、可移動的存儲單位有獨(dú)立句柄分析 Chunk 句柄和副本管理流程以為追加寫保證不重復(fù)Record Append 寫入一次后不再出現(xiàn)至少一次語義可能重復(fù)看論文中重復(fù)和原子性說明以為 Master 保存所有副本位置Master 持久化所有副本位置副本位置信息不持久化靠心跳重建閱讀 Master 元數(shù)據(jù)說明以為租約只用于 Master 選主租約只是主節(jié)點(diǎn)授權(quán)租約用于 ChunkServer 寫授權(quán)避免并發(fā)寫沖突分析寫流程中的租約獲取如果在學(xué)習(xí)時(shí)發(fā)現(xiàn)“這個設(shè)計(jì)不合理”先別急著否定。GFS 的價(jià)值恰恰在于你能看明白它的每一個不合理之處才說明你理解了它背后的約束條件。比如“延遲刪除”看起來浪費(fèi)磁盤但在分布式系統(tǒng)里延遲刪除能換來恢復(fù)能力和更簡單的狀態(tài)機(jī)。10. 最佳實(shí)踐把 GFS 思想用在工程里學(xué)習(xí) GFS 不是為了讓面試官滿意更重要的是把這些設(shè)計(jì)思想帶到實(shí)際系統(tǒng)設(shè)計(jì)里。下面幾條是我在實(shí)際工程中最常借鑒的。第一先定義負(fù)載再選架構(gòu)。不是所有文件系統(tǒng)都需要 POSIX也不是所有存儲都需要強(qiáng)一致。如果你的業(yè)務(wù)是日志收集、事件流、批量 ETLGFS 風(fēng)格的大文件追加寫模型能帶來極高吞吐如果業(yè)務(wù)是電商訂單這類強(qiáng)一致事務(wù)就不適合。第二用大塊降低元數(shù)據(jù)規(guī)模。設(shè)計(jì)分布式對象存儲時(shí)把對象切分為較大的分片比如 64MB 或更大減少索引條目數(shù)量這樣元數(shù)據(jù)服務(wù)壓力會小很多。代價(jià)是空間分配有碎片小對象會浪費(fèi)空間需要根據(jù)對象大小分布來選擇分片大小。第三寫操作必須配操作日志。主節(jié)點(diǎn)元數(shù)據(jù)一旦丟失整個集群就廢了。操作日志加 Checkpoint 是最簡單的恢復(fù)方案成本低、實(shí)現(xiàn)簡單HDFS 的 FsImage EditLog 就是這么做的。第四用租約而不是鎖服務(wù)選主。當(dāng)沒有強(qiáng)一致性要求時(shí)租約機(jī)制可以用非常簡單的代碼實(shí)現(xiàn)寫權(quán)限控制。如果要求高可用再加主備切換和共識協(xié)議。第五批量任務(wù)一定要冪等。GFS 的追加寫至少一次語義意味著下游處理程序要做好重復(fù)數(shù)據(jù)處理。在實(shí)際工程中凡是依賴分布式文件系統(tǒng)做消息或日志存儲的場景消費(fèi)端都應(yīng)該按唯一 ID 去重。第六做容量規(guī)劃時(shí)給副本留余量。默認(rèn) 3 副本意味著你的物理存儲成本是邏輯數(shù)據(jù)的 3 倍但壞一個節(jié)點(diǎn)后系統(tǒng)要立刻復(fù)制新副本又會觸發(fā)更多磁盤 IO。生產(chǎn)環(huán)境建議把磁盤水位控制在 70% 左右給副本復(fù)制和臨時(shí)文件留空間。11. 總結(jié)與下一步GFS 最值得花時(shí)間研究的點(diǎn)不是它的具體參數(shù)而是它如何從負(fù)載特征推導(dǎo)出架構(gòu)選擇大文件順序讀導(dǎo)致了大塊設(shè)計(jì)可靠性要求導(dǎo)致了 3 副本和自動恢復(fù)弱一致性要求導(dǎo)致了簡潔的寫路徑和追加寫模型。把這套“先定義問題、再選擇方案”的思維方式拿下來比記住 64MB、3 副本這些數(shù)字重要得多。接下來可以按兩條線繼續(xù)深挖。第一條線是讀論文原文重點(diǎn)看第 3 章架構(gòu)設(shè)計(jì)、第 4 章交互流程和第 5 章一致性模型論文里的圖對理解流程非常關(guān)鍵。第二條線是上手 HDFS在一個小集群上實(shí)際執(zhí)行文件讀寫觀察 NameNode 元數(shù)據(jù)變化、DataNode 心跳和副本復(fù)制過程把 GFS 的抽象概念落到真實(shí)系統(tǒng)上。如果目標(biāo)是應(yīng)對系統(tǒng)設(shè)計(jì)面試建議把寫流程和一致性模型練到“不看筆記能畫流程圖”的程度。這兩個點(diǎn)是面試官最常追問的細(xì)節(jié)也是區(qū)分“看過概述”和“真正理解”的分水嶺。后續(xù)還可以對比閱讀 BigTable 論文和 Chubby 鎖服務(wù)的論文這三篇加起來基本構(gòu)成了 Google 早期分布式系統(tǒng)的三大支柱也是進(jìn)入分布式系統(tǒng)領(lǐng)域的最佳教材組合。