??Google File System(簡稱GFS)是適用于大規(guī)模且可擴展的分布式文件系統(tǒng),可以部署在廉價的商務服務器上,在保證系統(tǒng)可靠性和可用 性的同時,大大降低了系統(tǒng)的成本。GFS的設計目標是高性能、高可靠、高可用性。
??GFS把機器故障視為正?,F(xiàn)象,可以很好地處理系統(tǒng)故障。GFS系統(tǒng)通常會部署在上百臺甚至上千臺廉價服務器上,并會有相當多臺廉價服務器上部署GFS Client來訪問GFS服務,所以應用故障、操作系統(tǒng)bug、連接故障、網絡故障、甚至機器供電故障都是經常發(fā)生的故障。GFS系統(tǒng)可以支持系統(tǒng)監(jiān)控、故障檢測、故障容忍和自動恢復,提供了非常高的可靠性。其次,GFS系統(tǒng)中的文件一般都是大文件,且文件操作大部分場景下都是append而不是overwrite。一旦文件寫入完成后,大部分操作都是讀文件且是順序讀。
??GFS提供了非標準(比如POSIX)的文件系統(tǒng)接口,支持 create、delete、open、close、read以及write。另外GFS支持snapshot和record append操作。snapshot可以以很低的代價創(chuàng)建文件或者目錄樹的拷貝,record append可以支持多個client并發(fā)地向同一個文件append data,同時還能保證每個client的append操作的原子性。
一、GFS架構
??GFS系統(tǒng)包括master、多個chunkserver以及多個client。文件被切分為固定大小的小文件(chunk)。每個chunk創(chuàng)建時,master會分配一個64bit的全局唯一且不可修改的chunk handler來標志這個chunk。chunkserver負責將chunk存儲在本地磁盤的Linux文件中,并通過chunk hander和byte range來讀寫chunk文件。為了提高可靠性,每個chunk都是多副本存儲在多個chunkserver上,默認情況下是三副本。用戶可以為不同名字空間下的文件配置不同的副本數。
??master記錄了文件系統(tǒng)的metadata,包括名字空間、權限控制信息、文件到chunk的mapping以及chunk的分布。master也負責chunk的lease管理、無用chunk的垃圾回收、chunk遷移等。master定期與chunkserver通信,向chunkserver發(fā)送指令并搜集chunkserver的狀態(tài)。GFS client通過GFS的API與GFS系統(tǒng)通信(讀寫數據)。client向master請求獲取metadata,真正的讀寫數據是直接與chunkserver交互。client和chunkserver都不cache文件數據。因為大部分應用都是基于API來streaming read 大文件且系統(tǒng)的文件數據太多,所以client緩存文件數據沒有意義。chunkserver所在機器的Linux的buffer cache以及cache了頻繁訪問的數據,chunkserver也是沒有去cache文件數據的。
二、Single Master
??單點master大大簡化了系統(tǒng)設計,因為master知曉所有的meta信息,所以可以執(zhí)行更加復雜的chunk位置分配和副本策略。但是,在讀寫數據時必須降低master的參與,以避免單點的master稱為系統(tǒng)瓶頸。client不會通過master來讀寫文件數據,但是client會向master發(fā)送查詢chunk位置分布的請求,然后client端緩存chunk的分布信息,然后直接向chunkserver讀寫數據。大致的讀過程如下:
1、client根據文件名、byte offset以及chunk size計算出要讀取的文件的chunk index
2、client通過文件名、chunk index向master查詢chunk的分布
3、master回復chunk handler以及副本分布
4、client 緩存chunk的meta信息,key由文件名和chunk index組成
5、client從chunk的分布信息中查找距離自己最新的chunkserver,并發(fā)送查詢請求。查詢請求中包括chunk hander以及byte range。后續(xù)對相同chunk的查詢不需要再次向master查詢meta信息,因為client已經緩存了meta信息。
三、chunk size
??chunk size是GFS系統(tǒng)的關鍵參數,通常設置為64MB,遠大于文件系統(tǒng)的block大小。每個chunk的副本都chunkserver所在機器上以Linux file存儲。之所為將chunk size定為64MB,主要有以下考慮:
1、可以減少client訪問master查詢meta信息的次數,降低master的訪問壓力。因為chunk size設計比較大,順序訪問一個超大文件時因為chunk數較少且client緩存了chunk meta信息,所以訪問master的次數就會降低。甚至,client可以緩存所有文件的chunk的meta信息,就算是隨機讀文件,master也不會成為系統(tǒng)性能瓶頸。
2、可以減少網絡開銷,保持client與chunkserver的TCP連接,可以執(zhí)行更多的chunk操作。
3、可以減少master上需要在內存中記錄的meta data數據量,降低master的內存占用。
?? size大的缺點是:小文件包含很少的chunk,甚至只有一個。這樣的話,在多個client高并發(fā)查詢該小文件時對應的chunk會成為熱點。實際上,這種情況在GFS系統(tǒng)中很少發(fā)生,因為大部分client的操作都是順序讀大文件。但是,考慮以下場景,我們部署一個服務的二進制文件到GFS系統(tǒng)中,然后數百臺的服務器同時查詢二進制文件并啟動服務,此時該二進制文件副本所在的chunkserver立馬就會成為查詢瓶頸。當然,可以通過增加副本數和分散服務器的查詢時間來解決這種場景下的問題。
四、Metadata
??master主要存儲三種類型的metadata:file和chunk的名字空間,file到chunk的mapping信息以及chunk的副本分布。所有的metadata都在master的內存中存儲。前兩種meta信息可以持久化存儲,將操作日志存儲在master的本地磁盤以及將備份日志存儲在遠端機器上。master不持久化存儲chunk的副本分布信息,而是通過與chunkserver交互來獲取chunkserver上的chunk信息。
4.1 in-memory data structure
??meta信息在內存中,所有master的操作很快。另外,master可以高效地定期在后臺scan所有的meta數據,來執(zhí)行垃圾回收、副本修復、均衡等。metadata都記錄在內存中,所以GFS系統(tǒng)會比較關注chunk的數量以及master的可用內存量。但是在實際場景下,這不是問題。每個64MB的chunk的metadata小于64字節(jié),大部分的chunk都是滿負荷存儲的,除了文件最后一個chunk的空間是沒有完全被占用。由于文件的名字空間采用了前綴壓縮的方式存儲,單個文件的meta信息也是小于64字節(jié)。如果需要擴大系統(tǒng)規(guī)模的話,可以很簡單地通過增大master的內存就可以了。相比于系統(tǒng)的高可靠、高性能和簡潔性,增加內存是很最小的代價了。
4.2 chunk 分布
??并沒有持久化存儲chunk的副本分布信息,而是在master啟動時向chunkserver查詢其chunk信息,然后通過heartbeat來持續(xù)更新master的副本分布信息,以與chunkserver數據保持一致。GFS起初設計時嘗試將chunk的分布信息持久化存儲在master端,隨后發(fā)現(xiàn)通過master啟動時拉取然后通過heartbeat同步chunk信息的方式更簡單。因為,當chunkserver加入、退出、名字改變、重啟等行為經常發(fā)生,這會導致維護master的chunk meta數據的正確性是非常困難的。從另一個角度考慮就是,只有chunkserver匯報的chunk信息才是集群中最真實的chunk分布,因為master不需要自己維護一個chunk分布狀態(tài),只需要以chunkserver的狀態(tài)匯報為準即可。
4.3 操作日志
??日志記錄了GFS集群數據更改的歷史記錄。操作日志對GFS來說是至關重要的,因為它不僅是metadata的持久化記錄,還記錄了并發(fā)操作的時序。因為操作日志很重要,所以必須可靠地存儲。在metadata的change沒有持久化之前,client是不能看到的數據的更改。當client修改數據時,操作記錄需要保存在多個遠端機器上,而且只有當操作記錄持久化存儲在本地和遠端以后,才會回復client數據更改成功。
??可以通過回放操作日志來恢復文件系統(tǒng)。為了減少系統(tǒng)啟動時replay的時間,必須縮減回放的日志量。master可以定期存儲metadata的checkpoint,master重啟時可以從checkpoint加載metadata,然后回放checkpoint之后的少量日志即可。
五、租約和數據更改
??數據更改主要指chunk的write或者append操作。數據的修改會在chunk的所有副本上執(zhí)行,GFS使用lease機制來保證chunk副本上修改操作的執(zhí)行順序。master將lease頒發(fā)給chunk的一個副本,稱之為primary,primary然后選擇chunk上其他副本的修改執(zhí)行順序。大概的執(zhí)行邏輯如下:
1、client向master查詢chunk的primary所在的chunkserver以及其他副本的分布,如果沒有primary的花,master會選擇一個作為該chunk的primary
2、master回復client primary和其他副本的分布信息。client會cache返回的metadata
3、client將數據發(fā)送所有的副本。client可以以任意順序執(zhí)行。每個chunkserser都會在內存的LRUbuffer中記錄數據。
4、當所有的副本都返回已經接收數據成功后,client會向primary發(fā)送一個寫請求。primary會為每一個數據更改的請求附加一個序列號,數據更改是按照序列號的順序執(zhí)行的。
5、primary將數據更改同步到其他副本中,副本也是按照序列號執(zhí)行數據更改操作。
6、primary接收到其他副本回復的數據操作完成
7、primary返回client結果。期間發(fā)生的所有錯誤都會報給client。
六、副本分布
?? GFS集群一般都會有上百臺的chunkserver,分布在多個機架上。chunkserver也會接收來自本機架或者其他機架的上百個client的查詢請求。不同機架的服務器通信可能會途徑一個或者多個交換機轉發(fā)。chunk的副本分布選擇策略主要目的是盡量提高數據的可靠性和可用性,同時最大化地充分利用網絡帶寬。所以,僅僅將副本跨機器部署是不夠的。GFS將副本是跨機架部署的,這樣可以保證在一個機架被損壞或者下線時,chunk至少會有副本是可用的。
?? chunk的副本在下列情況下會被創(chuàng)建:創(chuàng)建chunk、副本修復、rebalance。當master創(chuàng)建chunk時,會選擇存儲該chunk副本的chunkserver。主要考慮以下幾點:
1、新副本所在chunkserver的磁盤利用率低于系統(tǒng)的平均水平
2、限制每個chunkserver最近一段時間創(chuàng)建chunk的數量
3、每個chunk的所有副本不能都在一個機架
?? chunk的副本數少于一定數量是,master會復制一個副本。這可能發(fā)生在chunkserver宕機或者chunkserver匯報自己的副本損壞或者chunkserver所在機器的磁盤損壞等等。每個chunk 復制任務都有優(yōu)先級,按照優(yōu)先級由高到低子master中排隊等待執(zhí)行。master還會定期掃描當前副本的分布情況,一旦發(fā)現(xiàn)磁盤使用量或者機器負載不均衡,就會發(fā)起負載均衡操作。無論是chunk創(chuàng)建、chunk復制還是負載均衡,選擇chunk副本的位置的策略都是相同的,并且需要限制副本修復和均衡的速度,否則會影響系統(tǒng)的正常讀寫服務。
??Google的成功表明單master的設計師可行的。這不僅簡化了系統(tǒng),而且能夠較好地實現(xiàn)一致性,給予性能考慮,GFS提出了“記錄至少原子性追加一次”的一致性模型。通過租約的方式將每個chunk的修改授權到chunkserver從而減少了master的負載,通過流水線的方式復制多個副本以減少延時。master維護的元數據很多,需要設計高效的數據結構,且要保證占用內存小和支持快照操作。支持COW的B樹可以滿足需求,但是實現(xiàn)確實相當復雜。