sina
Google File System距糖,一個(gè)適用于大規(guī)模分布式數(shù)據(jù)處理相關(guān)應(yīng)用的玄窝,可擴(kuò)展的分布式文件系統(tǒng)。
GFS 提供了常見(jiàn)的文件系統(tǒng)的接口悍引,文件是通過(guò)pathname 來(lái)通過(guò)目錄進(jìn)行分層管理的恩脂。我們支持的一些常見(jiàn)操作:create,delete,open,close,read,write 等文件操作趣斤。另外俩块,GFS 有snapshot,record append 等操作唬渗。snapshort 創(chuàng)建一個(gè)文件或者一個(gè)目錄樹(shù)的快照典阵,這個(gè)快照的耗費(fèi)比較低。record append 允許很多個(gè)客戶端同時(shí)對(duì)一個(gè)文件增加數(shù)據(jù)镊逝,同時(shí)保證每一個(gè)客戶端的添加操作的原子操作性。這個(gè)對(duì)于多路合并操作和多個(gè)客戶端同時(shí)操作的生產(chǎn)者/消費(fèi)者隊(duì)列的實(shí)現(xiàn)非常有用嫉鲸,它不用額外的加鎖處理撑蒜。
如上圖所示,GFS 集群由一個(gè)單個(gè)的master 和好多個(gè)chunkserver(塊服務(wù)器)組成玄渗,GFS 集群會(huì)有很多客戶端client 訪問(wèn)座菠。每一個(gè)節(jié)點(diǎn)都是一個(gè)普通的Linux 計(jì)算機(jī),運(yùn)行的是一個(gè)用戶級(jí)別(user-level)的服務(wù)器進(jìn)程藤树。只要機(jī)器資源允許浴滴,并且允許不穩(wěn)定的應(yīng)用代碼導(dǎo)致的低可靠性,我們就可以運(yùn)行chunkserver 和client 可以運(yùn)行在同一個(gè)機(jī)器上岁钓。
在 GFS 下升略,每一個(gè)文件都拆成固定大小的chunk(塊)。每一個(gè)塊都由master 根據(jù)塊創(chuàng)建的時(shí)間產(chǎn)生一個(gè)全局唯一的以后不會(huì)改變的64 位的chunk handle 標(biāo)志屡限。chunkservers 在本地磁盤上用Linux文件系統(tǒng)保存這些塊品嚣,并且根據(jù)chunk handle 和字節(jié)區(qū)間,通過(guò)Linux 文件系統(tǒng)讀寫這些塊的數(shù)據(jù)钧大。出于可靠性的考慮翰撑,每一個(gè)塊都會(huì)在不同的chunkserver 上保存?zhèn)浞荨H笔∏闆r下啊央,我們保存3 個(gè)備份眶诈,不過(guò)用戶對(duì)于不同的文件namespace 區(qū)域涨醋,指定不同的復(fù)制級(jí)別逝撬。
master 負(fù)責(zé)管理所有的文件系統(tǒng)的元數(shù)據(jù)东帅。包括namespace,訪問(wèn)控制信息球拦,文件到chunk 的映射關(guān)系靠闭,當(dāng)前chunk 的位置等等信息。master 也同樣控制系統(tǒng)級(jí)別的活動(dòng)坎炼,比如chunk 的分配管理愧膀,孤點(diǎn)chunk 的垃圾回收機(jī)制,chunkserver 之間的chunk 鏡像管理谣光。master 和這些chunkserver 之間會(huì)有定期的心跳線進(jìn)行通訊檩淋,并且心跳線傳遞信息和chunckserver 的狀態(tài)。
這里我們簡(jiǎn)單介紹一下上圖 中的讀取操作萄金。首先蟀悦,客戶端把應(yīng)用要讀取的文件名和偏移量,根據(jù)固定的chunk 大小氧敢,轉(zhuǎn)換成為文件的chunk index日戈。然后向master 發(fā)送這個(gè)包含了文件名和chunkindex的請(qǐng)求。master 返回相關(guān)的chunk handle 以及對(duì)應(yīng)的位置孙乖≌懔叮客戶端cache 這些信息,把文件名和chunkindex 作為cache 的關(guān)鍵索引字唯袄。
于是這個(gè)客戶端就像對(duì)應(yīng)的位置的chunkserver 發(fā)起請(qǐng)求弯屈,通常這個(gè)會(huì)是離這個(gè)客戶端最近的一個(gè)。請(qǐng)求給定了chunk handle 以及一個(gè)在這個(gè)chunk 內(nèi)需要讀取得字節(jié)區(qū)間恋拷。在這個(gè)chunk 內(nèi)资厉,再次操作數(shù)據(jù)將不用再通過(guò)客戶端-master 的交互,除非這個(gè)客戶端本身的cache 信息過(guò)期了蔬顾,或者這個(gè)文件重新打開(kāi)了宴偿。實(shí)際上,客戶端通常都會(huì)在請(qǐng)求中附加向master 詢問(wèn)多個(gè)chunk 的信息阎抒,master于是接著會(huì)立刻給這個(gè)客戶端回應(yīng)這些chunk 的信息酪我。這個(gè)附加信息是通過(guò)幾個(gè)幾乎沒(méi)有任何代價(jià)的客戶端-master 的交互完成的。
chunk 的大小是一個(gè)設(shè)計(jì)的關(guān)鍵參數(shù)且叁。選擇一個(gè)很大的chunk 大小提供了一些重要的好處都哭,減少了客戶端和master 的交互,因?yàn)樵谕粋€(gè)chunk 內(nèi)的讀寫操作只需要客戶端初始詢問(wèn)一次master 關(guān)于chunk 位置信息就可以了∑劢茫可以通過(guò)維持一個(gè)到chunkserver 的TCP 長(zhǎng)連接來(lái)減少網(wǎng)絡(luò)管理量纱新,減少了元數(shù)據(jù)在master 上的大小,這個(gè)使得我們可以把元數(shù)據(jù)保存在內(nèi)存穆趴。
元數(shù)據(jù):
master 節(jié)點(diǎn)保存這樣三個(gè)主要類型的數(shù)據(jù):文件和chunk 的namespace脸爱,文件到chunks 的映射關(guān)系,每一個(gè)chunk 的副本的位置未妹。頭兩個(gè)類型(namepspaces 和文件到chunk 的映射)同時(shí)也是由在master 本地硬盤的記錄所有變化信息的operation log (操作記錄保存了關(guān)鍵的元數(shù)據(jù)變化歷史記錄簿废。它是GFS 的核心。不僅僅因?yàn)檫@是唯一持久化的元數(shù)據(jù)記錄络它,而且也是因?yàn)椴僮饔涗浺彩亲鳛檫壿嫊r(shí)間基線族檬,定義了并行操作的順序)來(lái)持久化保存的,這個(gè)記錄也會(huì)在遠(yuǎn)端機(jī)器上保存副本化戳。通過(guò)log单料,在master 宕機(jī)的時(shí)候,我們可以簡(jiǎn)單点楼,可靠的恢復(fù)master 的狀態(tài)扫尖。master 并不持久化保存chunk 位置信息。相反掠廓,他在啟動(dòng)地時(shí)候以及chunkserver 加入集群的時(shí)候换怖,向每一個(gè)chunkserver 詢問(wèn)他的chunk 信息。
操作記錄(operation log)
我們把這個(gè)日志文件保存在多個(gè)不同的主機(jī)上却盘,并且只有當(dāng)刷新這個(gè)相關(guān)的操作記錄到本地和遠(yuǎn)程磁盤之后狰域,才會(huì)給客戶端操作應(yīng)答。master 可以每次刷新一批日志記錄黄橘,以減少刷新和復(fù)制這個(gè)日志導(dǎo)致的系統(tǒng)吞吐量。
為了減少啟動(dòng)時(shí)間屈溉,我們必須盡量減少操作日志的大小塞关。master 在日志增長(zhǎng)超過(guò)某一個(gè)大小的時(shí)候,執(zhí)行checkpoint 動(dòng)作子巾,卸出自己的狀態(tài)帆赢,這樣可以使下次啟動(dòng)的時(shí)候從本地硬盤讀出這個(gè)最新的checkpoint,然后反演有限記錄數(shù)线梗。
checkpoint 是一個(gè)類似B-樹(shù)的格式椰于,可以直接映射到內(nèi)存,而不需要額外的分析仪搔。這更進(jìn)一步加快了恢復(fù)的速度瘾婿,提高了可用性。因?yàn)榻⒁粋€(gè)checkpoint 可能會(huì)花一點(diǎn)時(shí)間,于是我們這樣設(shè)定master 的內(nèi)部狀態(tài)偏陪,就是說(shuō)新建立的checkpoint 可以不阻塞新的狀態(tài)變化抢呆。master 切換到一個(gè)新的log 文件,并且在一個(gè)獨(dú)立的線程中創(chuàng)建新的checkpoint笛谦。新的checkpoint 包含了在切換到新log 文件之前的狀態(tài)變化抱虐。當(dāng)這個(gè)集群有數(shù)百萬(wàn)文件的時(shí)候,創(chuàng)建新的checkpoint 會(huì)花上幾分鐘的時(shí)間饥脑。當(dāng)checkpoint 建立完畢恳邀,會(huì)寫到本地和遠(yuǎn)程的磁盤。
對(duì)于 master 的恢復(fù)灶轰,只需要最新的checkpoint 以及后續(xù)的log 文件谣沸。舊的checkpoint 及其log 文件可以刪掉了,雖然我們還是保存幾個(gè)checkpoint 以及l(fā)og框往,用來(lái)防止比較大的故障產(chǎn)生鳄抒。在checkpoint的時(shí)候得故障并不會(huì)導(dǎo)致正確性受到影響,因?yàn)榛謴?fù)的代碼會(huì)檢查并且跳過(guò)不完整的checkpoint椰弊。
一致性模型
文件名字空間的改變(比如许溅,文件的創(chuàng)建)是原子操作。他們是由master 來(lái)專門處理的秉版。名字空間的鎖定保證了操作的原子性以及正確性贤重;master 的操作日志定義了這些操作的全局順序。
namespace 管理及鎖定
GFS 從邏輯上是通過(guò)一個(gè)查找路徑名到元數(shù)據(jù)映射表的方式來(lái)體現(xiàn)namespace 的清焕。通過(guò)前綴壓縮并蝗,這個(gè)表可以有效地在內(nèi)存中存放。每一個(gè)namespace 樹(shù)種的節(jié)點(diǎn)(不論是絕對(duì)文件名還是絕對(duì)目錄名)秸妥,都有一個(gè)相關(guān)的讀寫鎖滚停。
副本位置
GFS 集群是在不止一個(gè)級(jí)別上的多級(jí)別的高度分布的系統(tǒng)。通常由好幾百臺(tái)分布在很多機(jī)架上的chunkserver 組成粥惧。這些chunkserver 可能被相同或者不同的機(jī)架的幾百臺(tái)客戶端輪流訪問(wèn)键畴。兩個(gè)機(jī)架上的兩臺(tái)機(jī)器可能會(huì)跨越不止一個(gè)網(wǎng)絡(luò)交換機(jī)。此外突雪,機(jī)架的入口帶寬或者出口帶寬往往會(huì)比在機(jī)架內(nèi)的機(jī)器聚合帶寬要小起惕。多級(jí)別的分布凸現(xiàn)了一個(gè)獨(dú)特的要求,為了可擴(kuò)展性咏删,可靠性惹想,以及可用性要把數(shù)據(jù)進(jìn)行分布。
數(shù)據(jù)完整性
每一個(gè)chunkserver 都是用checksum 來(lái)檢查保存數(shù)據(jù)的完整性督函。通常一個(gè)GFS 集群都有好幾百臺(tái)機(jī)器以及幾千塊硬盤嘀粱,磁盤損壞是很經(jīng)常的事情激挪,在數(shù)據(jù)的讀寫中經(jīng)常出現(xiàn)數(shù)據(jù)損壞。我們可以通過(guò)別的chunk 副本來(lái)解決這個(gè)問(wèn)題草穆,但是如果跨越chunkserver 比較這個(gè)chunk的內(nèi)容來(lái)決定是否損壞就很不實(shí)際灌灾。進(jìn)一步說(shuō),允許不同副本的存在;在GFS 更改操作的語(yǔ)義上悲柱,特別是早先討論過(guò)的原子紀(jì)錄增加的情況下锋喜,并不保證byte 級(jí)別的副本相同。因此豌鸡,每一個(gè)chunkserver上必須獨(dú)立的效驗(yàn)自己的副本的完整性嘿般,并且自己管理checksum。
我們把一個(gè)chunk 分成64k 的塊涯冠。每一個(gè)都有相對(duì)應(yīng)的32 位的checksum炉奴。就像其他的元數(shù)據(jù)一樣,checksum 是在內(nèi)存中保存的蛇更,并且通過(guò)分別記錄用戶數(shù)據(jù)來(lái)持久化保存瞻赶。對(duì)于讀操作來(lái)說(shuō),在給客戶端或者chunkserver 讀者返回?cái)?shù)據(jù)之前派任,chunkserver 效驗(yàn)要被讀取的數(shù)據(jù)所在塊的checksum砸逊。因此chunkserver 不會(huì)把錯(cuò)誤帶給其他設(shè)備。如果一個(gè)塊的checksum 不正
確掌逛,chunkserver 會(huì)給請(qǐng)求者一個(gè)錯(cuò)誤师逸,并且告知master 這個(gè)錯(cuò)誤。收到這個(gè)應(yīng)答之后豆混,請(qǐng)求者應(yīng)當(dāng)從其他副本讀取這個(gè)數(shù)據(jù)篓像,master 也會(huì)安排從其他副本來(lái)做克隆。當(dāng)一個(gè)新的副本就緒后皿伺,master會(huì)指揮剛才報(bào)錯(cuò)的chunkserver 刪掉它剛才錯(cuò)誤的副本员辩。checksum 對(duì)于讀取性能來(lái)說(shuō),在幾方面有點(diǎn)影響鸵鸥。因?yàn)榇蟛糠值淖x取操作都分布在好幾個(gè)block 上屈暗,我們只需要額外的多讀取一小部分相關(guān)數(shù)據(jù)進(jìn)行checksum 檢查。GFS 客戶端代碼通過(guò)每次把讀取操作都對(duì)齊在block 邊界上脂男,來(lái)進(jìn)一步減少了這些額外的讀取。此外种呐,在chunkserver 上的checksum的查找和比較不需要附加的I/O宰翅,checksum 的計(jì)算可以和I/O 操作同時(shí)進(jìn)行。
checksum 的計(jì)算是針對(duì)添加到chunk 尾部的寫入操作作了高強(qiáng)度的優(yōu)化(和改寫現(xiàn)有數(shù)據(jù)不同)爽室,因?yàn)樗鼈冿@然占據(jù)主要工作任務(wù)汁讼。我們?cè)隽扛玛P(guān)于最后block 的checksum 部分,并且計(jì)算添加操作導(dǎo)致的新的checksum block 部分。即使是某一個(gè)checksum 塊已經(jīng)損壞了嘿架,但是我們?cè)趯懙脮r(shí)候并不立刻檢查瓶珊,新的checksum 值也不會(huì)和已有數(shù)據(jù)吻合,下次對(duì)這個(gè)block 的讀取的時(shí)候耸彪,會(huì)檢查出這個(gè)損壞的block伞芹。
另一方面,如果寫操作基于一個(gè)已有的chunk(而不是在最后追加)蝉娜,我們必須讀取和效驗(yàn)被寫得第一個(gè)和最后一個(gè)block唱较,然后再作寫操作,最后計(jì)算和寫入新的checksum召川。如果我們不效驗(yàn)第一個(gè)和最后一個(gè)被寫得block南缓,那么新的checksum 可能會(huì)隱藏沒(méi)有改寫區(qū)域的損壞部分。
在 chunkserver 空閑的時(shí)候荧呐,他掃描和效驗(yàn)每一個(gè)非活動(dòng)的chunk 的內(nèi)容汉形。這使得我們能夠檢查不常用的chunk 塊的完整性。一旦發(fā)現(xiàn)這樣的塊有損壞倍阐,master 可以創(chuàng)建一個(gè)新的正確的副本概疆,然后把這個(gè)損壞的副本刪除。這個(gè)機(jī)制防止了非活動(dòng)的塊損壞的時(shí)候收捣,master 還以為這些非活動(dòng)塊都已經(jīng)有了足夠多的副本届案。