Architecture
-
一個(gè)GFS Cluster由一個(gè)master和多個(gè)chunkserver組成
一個(gè)文件會(huì)被切分為固定大邪舐濉(64MB)的chunk瘩缆。在創(chuàng)建chunk時(shí)击孩,master會(huì)分配一個(gè)64bit的全局唯一且不可修改的 chunk handler 來標(biāo)志這個(gè)chunk颤难。
chunkserver 將chunk存儲(chǔ)在本地磁盤中臂痕,并通過chunk hander和byte range來讀寫chunk文件。為了可靠性,chunk被復(fù)制多份 chunk replica 存儲(chǔ)在不同的chunkserver上(默認(rèn)3份,用戶也可以對(duì)文件系統(tǒng)名字空間的不同地方設(shè)置不同的復(fù)制份數(shù))旬牲。
GFS client為應(yīng)用程序提供了文件系統(tǒng)API),包括create, delete, open, close, read, write, record append等(但沒有實(shí)現(xiàn)POSIX的標(biāo)準(zhǔn)接口)搁吓。Client在和master交互元數(shù)據(jù)后原茅,直接和chunkserver交互進(jìn)行讀寫數(shù)據(jù)。
Master
- Master負(fù)責(zé)維護(hù)文件系統(tǒng)的所有元數(shù)據(jù)(metadata)堕仔,包括:命名空間(namespace擂橘,也就是常規(guī)文件系統(tǒng)的中的文件樹),訪問權(quán)限摩骨,文件到chunk的映射通贞,每個(gè)chunk replica的當(dāng)前位置等朗若。
Metadata
- 所有的元數(shù)據(jù)都存儲(chǔ)在master的內(nèi)存里。
- master會(huì)將命名空間昌罩,文件到chunk的映射等信息通過 operation log 的方式進(jìn)行持久化到本地磁盤哭懈,再備份到遠(yuǎn)程機(jī)器。在metadata的change沒有持久化之前茎用,client是不能看到的數(shù)據(jù)的更改遣总。而且只有當(dāng)操作記錄持久化存儲(chǔ)在本地和遠(yuǎn)端以后,才會(huì)回復(fù)client數(shù)據(jù)更改成功绘搞。
- 而chunk replica的當(dāng)前位置信息不會(huì)被持久化彤避,而是在master啟動(dòng)時(shí)向chunkserver查詢其chunk信息,然后通過 heartbeat 來持續(xù)更新master的副本分布信息夯辖,以與chunkserver數(shù)據(jù)保持一致琉预。
- 可以通過回放operation log恢復(fù)文件系統(tǒng)。為了減少系統(tǒng)啟動(dòng)時(shí)的恢復(fù)時(shí)間蒿褂,master可以定期存儲(chǔ)metadata的 checkpoint 圆米,master重啟時(shí)可以從checkpoint加載metadata(checkpoint是類似B-Tree的數(shù)據(jù)結(jié)構(gòu),可以直接加載進(jìn)內(nèi)存)啄栓,然后回放checkpoint之后的少量日志即可娄帖。
數(shù)據(jù)更改
- 數(shù)據(jù)修改包括chunk的write或者append操作:
- write:寫數(shù)據(jù)到應(yīng)用程序指定的file offset
- append:將數(shù)據(jù)(record)至少一次原子性的append到文件中,offset由GFS選擇(通常是將data append到某個(gè)文件的尾部)昙楚。 這個(gè)offset會(huì)返回給客戶端
- 數(shù)據(jù)的修改會(huì)在chunk的所有副本上執(zhí)行近速,GFS使用 lease 機(jī)制來保證chunk副本上修改操作的執(zhí)行順序。master將lease頒發(fā)給chunk的一個(gè)副本堪旧,稱之為 primary 削葱,primary然后選擇chunk上其他replica(稱為secondary)的修改執(zhí)行順序。具體步驟為:
- client向master查詢chunk的primary和secondary所在的chunkserver淳梦,如果沒有一個(gè)replica擁有l(wèi)ease析砸,master會(huì)選擇一個(gè)replica并授予lease(需要等待lease過期,以防止腦裂)
- master返回primary和secondary的信息爆袍。client會(huì)cache返回的信息首繁。直到primary不擁有l(wèi)ease(默認(rèn)持有l(wèi)ease 60秒)或不可訪問,client將需要再次請(qǐng)求master陨囊。
- client將數(shù)據(jù)發(fā)送給所有的replica弦疮,順序可以是任意的。每個(gè)chunkserser會(huì)將數(shù)據(jù)存儲(chǔ)在內(nèi)存的LRU buffer cache中蜘醋。
- 當(dāng)所有的副本都返回已經(jīng)接收數(shù)據(jù)成功后挂捅,client會(huì)向primary發(fā)送一個(gè)寫請(qǐng)求。primary會(huì)為每一個(gè)數(shù)據(jù)更改的請(qǐng)求附加一個(gè)序列號(hào)堂湖,primary按照序列號(hào)順序執(zhí)行本地?cái)?shù)據(jù)更改闲先。
- primary傳遞數(shù)據(jù)更改請(qǐng)求到secondary中,這些replica也按照序列號(hào)順序執(zhí)行本地?cái)?shù)據(jù)更改无蜂。
- secondary完成數(shù)據(jù)更改后伺糠,回復(fù)primary
- primary回復(fù)client。期間發(fā)生的所有錯(cuò)誤都會(huì)報(bào)給client斥季,表示請(qǐng)求失敗训桶。客戶端會(huì)重試酣倾,直到成功舵揭。
- 如果客戶端寫操作的數(shù)據(jù)跨了chunk的邊界,那么寫操作會(huì)被分割成多個(gè)chunk上的寫操作躁锡,每個(gè)chunk上的寫操作遵循上面的流程午绳。各個(gè)chunk上寫寫操作可能會(huì)被來自其他的客戶端的寫操作交錯(cuò)并覆蓋。
Data Flow
- 每個(gè)chunkserver傳輸數(shù)據(jù)給在網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)中最近的還沒收到數(shù)據(jù)的chunkserver映之。
Atomic Record Append
- 如果record append在某個(gè)replica上失敗了拦焚,client會(huì)進(jìn)行重試。因此可能造成同一個(gè)chunk的不同的replicas包含不一樣的數(shù)據(jù)杠输,有的replica有重復(fù)的record赎败,或者包含record的一部分。GFS不保證不同的replicas的數(shù)據(jù)每個(gè)bit都是一樣的蠢甲,但保證如果record append操作成功了僵刮,數(shù)據(jù)在同一個(gè)chunk的所有的replicas的offset是相同的。
Snapshot
- GFS使用copy-on-write的方法實(shí)現(xiàn)Snapshot鹦牛。具體操作步驟為:
- 當(dāng)master收到snapshot的請(qǐng)求時(shí)搞糕,會(huì)收回snapshot涉及的文件的chunk的lease,之后client對(duì)相關(guān)文件進(jìn)行寫操作時(shí)能岩,primary將回復(fù)client它已經(jīng)不再hold lease寞宫,使其必須與master進(jìn)行交互。
- master執(zhí)行snapshot操作拉鹃,即將chunk的引用計(jì)數(shù)+1辈赋,復(fù)制源文件或者目錄樹相關(guān)的元數(shù)據(jù),這份元數(shù)據(jù)也指向相同的chunk
- snapshot操作過后膏燕,當(dāng)client對(duì)chunk C進(jìn)行寫操作時(shí)钥屈,它詢問master哪個(gè)replica持有chunk C的lease,這時(shí)坝辫,master發(fā)現(xiàn)chunk C的引用計(jì)數(shù)大于1篷就,master將推遲回復(fù)客戶端并
選出一個(gè)新的chunk handle C'。然后讓有chunk C replica的chunkserver 在本地復(fù)制出chunk C'出來近忙,這個(gè)chunk就叫做C' - master授予lease給其中一個(gè)replica竭业,最后回復(fù)客戶端智润。后續(xù)的操作就和之前相同了。
命名空間管理和鎖
- 邏輯上來說未辆,GFS命名空間是一個(gè)文件完整路徑名到元數(shù)據(jù)的lookup表窟绷。
- 命名空間樹上的每個(gè)節(jié)點(diǎn)(一個(gè)
絕對(duì)路徑的文件名,或一個(gè)絕對(duì)路徑的目錄名)都有一個(gè)讀寫鎖咐柜。 - 創(chuàng)建一個(gè)文件時(shí)兼蜈,回對(duì)相關(guān)路徑上讀鎖,對(duì)文件上寫鎖拙友。
創(chuàng)建为狸,再次復(fù)制,重新負(fù)載均衡
- chunk replica創(chuàng)建的原因有三種:1. chunk的創(chuàng)建 2. 再次復(fù)制 3. 重新負(fù)載均衡
- 當(dāng)master創(chuàng)建一個(gè)chunk的時(shí)候遗契,它選擇在哪里放置新的空的replica辐棒。主要考慮如下因素:
- chunkserver上面磁盤的利用率,盡量將replica放到低磁盤利用率的機(jī)器上
- 限制chunkserver機(jī)器最近的創(chuàng)建的數(shù)目姊途,為了防止單個(gè)chunkserver壓力過大
- 盡可能將replicas散布在不同的機(jī)架
- 當(dāng)replica因?yàn)榇疟P損壞等原因unavailable涉瘾,replica數(shù)量低于設(shè)置閾值時(shí),master會(huì)再次復(fù)制生成replica捷兰。master選擇優(yōu)先級(jí)最高的chunk立叛,然后指示一個(gè)chunkserver從一個(gè)已經(jīng)存在的合法的replica上復(fù)制一份,同樣贡茅,replica的放置規(guī)則也會(huì)考慮前面提到的放置因素秘蛇。復(fù)制的chunk的優(yōu)先級(jí)基于以下幾個(gè)因素:
- 當(dāng)前replica數(shù)量離目標(biāo)數(shù)量的差距
- 趨向于復(fù)制live file的chunk,而不是deleted file的chunk
- 為了最小化失敗對(duì)應(yīng)用程序的影響顶考,可能會(huì)阻塞客戶端過程的chunk的優(yōu)先級(jí)更高赁还。
- master周期性地檢查replica的分布,進(jìn)行重新負(fù)載均衡驹沿,
垃圾回收
- 當(dāng)刪除一個(gè)文件后艘策,master會(huì)立刻把這個(gè)刪除操作記錄在日志里,但這個(gè)刪除操作并沒有立即實(shí)際執(zhí)行渊季,它只是把這個(gè)文件重命名了為一個(gè)包含時(shí)間戳的隱藏文件朋蔫。后面master定期掃描所有文件(namespace)時(shí),如果文件為隱藏文件却汉,會(huì)比較這個(gè)隱藏文件中的時(shí)間戳和現(xiàn)在的時(shí)間驯妄,如果超過3天(過期時(shí)間可配置)才真正刪除文件。但在這個(gè)期限之內(nèi)合砂,這個(gè)隱藏文件依然可以被讀到青扔。
- master 不能識(shí)別的replica是垃圾
- GFS允許設(shè)置立即刪除模式以快速釋放存儲(chǔ)空間,不同命名空間可以制定不同的復(fù)制和回收策略。
過期失效的replica檢測(cè)
- replica可能因?yàn)閏hunkserver 失效微猖,丟失了一些數(shù)據(jù)修改記錄
- master 通過 Chunk 的版本號(hào)區(qū)分up-to-date replica和過期的replica
- master 授予lease時(shí)增加版本號(hào)谈息,然后通知replica。master和replica都會(huì)將該版本號(hào)信息進(jìn)行持久化励两。
- master 會(huì)在垃圾回收的過程中移除過期失效的replica
數(shù)據(jù)完整性(Data Integrity)
- Chunkserver 使用 checksum 來檢查數(shù)據(jù)完整性黎茎。
- 每個(gè) Chunk 分為 64KB 的 block,每個(gè) block 對(duì)應(yīng)一個(gè) 32位的 Checksum当悔。checksum存儲(chǔ)在內(nèi)存中,并以日志的方式進(jìn)行持久化在和用戶數(shù)據(jù)分開的地方踢代。
- 讀操作時(shí)會(huì)檢查 checksum 是否正確盲憎,如果不正確,會(huì)返回client錯(cuò)誤信息胳挎,并告知master饼疙。client將從其它replica讀取信息。同時(shí)master將從其它replica復(fù)制數(shù)據(jù)對(duì)其進(jìn)行恢復(fù)慕爬。
- Checksum 效驗(yàn)不需要額外 IO窑眯,對(duì)性能影響小。并且Checksum 對(duì) Chunk append寫入操作做了優(yōu)化医窿,只增量更新最后一個(gè)不完整 block 的 Checksum