Google文件系統
GFS是一個可擴展的分佈式文件系統,用於大型的、分佈式的、對大量數據進行訪問的應用。它運行於廉價的普通硬件上,但能夠提供容錯功能。它能夠給大量的用戶提供整體性能較高的服務。
1、設計概覽
(1)設計想定
GFS與過去的分佈式文件系統有不少相同的目標,但GFS的設計受到了當前及預期的應用方面的工做量及技術環境的驅動,這反映了它與早期的文件系統明顯不一樣的設想。這就須要對傳統的選擇進行從新檢驗並進行徹底不一樣的設計觀點的探索。
GFS與以往的文件系統的不一樣的觀點以下:
1、部件錯誤再也不被看成異常,而是將其做爲常見的狀況加以處理。由於文件系統由成百上千個用於存儲的機器構成,而這些機器是由廉價的普通部件組成並被大量的客戶機訪問。部件的數量和質量使得一些機器隨時都有可能沒法工做而且有一部分還可能沒法恢復。因此實時地監控、錯誤檢測、容錯、自動恢復對系統來講必不可少。
2、按照傳統的標準,文件都很是大。長度達幾個GB的文件是很日常的。每一個文件一般包含不少應用對象。當常常要處理快速增加的、包含數以萬計的對象、長度達TB的數據集時,咱們很難管理成千上萬的KB規模的文件塊,即便底層文件系統提供支持。所以,設計中操做的參數、塊的大小必需要從新考慮。對大型的文件的管理必定要能作到高效,對小型的文件也必須支持,但沒必要優化。
3、大部分文件的更新是經過添加新數據完成的,而不是改變已存在的數據。在一個文件中隨機的操做在實踐中幾乎不存在。一旦寫完,文件就只可讀,不少數據都有這些特性。一些數據可能組成一個大倉庫以供數據分析程序掃描。有些是運行中的程序連續產生的數據流。有些是檔案性質的數據,有些是在某個機器上產生、在另一個機器上處理的中間數據。因爲這些對大型文件的訪問方式,添加操做成爲性能優化和原子性保證的焦點。而在客戶機中緩存數據塊則失去了吸引力。
4、工做量主要由兩種讀操做構成:對大量數據的流方式的讀操做和對少許數據的隨機方式的讀操做。在前一種讀操做中,可能要讀幾百KB,一般達 1MB和更多。來自同一個客戶的連續操做一般會讀文件的一個連續的區域。隨機的讀操做一般在一個隨機的偏移處讀幾個KB。性能敏感的應用程序一般將對少許數據的讀操做進行分類並進行批處理以使得讀操做穩定地向前推動,而不要讓它來來回回的讀。
5、工做量還包含許多對大量數據進行的、連續的、向文件添加數據的寫操做。所寫的數據的規模和讀類似。一旦寫完,文件不多改動。在隨機位置對少許數據的寫操做也支持,但沒必要很是高效。
6、系統必須高效地實現定義無缺的大量客戶同時向同一個文件的添加操做的語義。
(2)系統接口
GFS提供了一個類似地文件系統界面,雖然它沒有向POSIX那樣實現標準的API。文件在目錄中按層次組織起來並由路徑名標識。
(3)體系結構:
一個GFS集羣由一個master和大量的chunkserver構成,並被許多客戶(Client)訪問。如圖1所示。Master和 chunkserver一般是運行用戶層服務進程的Linux機器。只要資源和可靠性容許,chunkserver和client能夠運行在同一個機器上。
文件被分紅固定大小的塊。每一個塊由一個不變的、全局惟一的64位的chunk-handle標識,chunk-handle是在塊建立時由 master分配的。ChunkServer將塊看成Linux文件存儲在本地磁盤並能夠讀和寫由chunk-handle和位區間指定的數據。出於可靠性考慮,每個塊被複制到多個chunkserver上。默認狀況下,保存3個副本,但這能夠由用戶指定。
Master維護文件系統因此的元數據(metadata),包括名字空間、訪問控制信息、從文件到塊的映射以及塊的當前位置。它也控制系統範圍的活動,如塊租約(lease)管理,孤兒塊的垃圾收集,chunkserver間的塊遷移。Master按期經過HeartBeat消息與每個 chunkserver通訊,給chunkserver傳遞指令並收集它的狀態。
與每一個應用相聯的GFS客戶代碼實現了文件系統的API並與master和chunkserver通訊以表明應用程序讀和寫數據。客戶與master的交換隻限於對元數據(metadata)的操做,全部數據方面的通訊都直接和chunkserver聯繫。
客戶和chunkserver都不緩存文件數據。由於用戶緩存的益處微乎其微,這是因爲數據太多或工做集太大而沒法緩存。不緩存數據簡化了客戶程序和整個系統,由於沒必要考慮緩存的一致性問題。但用戶緩存元數據(metadata)。Chunkserver也沒必要緩存文件,由於塊時做爲本地文件存儲的。
(4)單master。
只有一個master也極大的簡化了設計並使得master能夠根據全局狀況做出先進的塊放置和複製決定。可是咱們必需要將master對讀和寫的參與減至最少,這樣它纔不會成爲系統的瓶頸。Client歷來不會從master讀和寫文件數據。Client只是詢問master它應該和哪一個 chunkserver聯繫。Client在一段限定的時間內將這些信息緩存,在後續的操做中Client直接和chunkserver交互。
以圖1解釋一下一個簡單的讀操做的交互。
1、client使用固定的塊大小將應用程序指定的文件名和字節偏移轉換成文件的一個塊索引(chunk index)。
2、給master發送一個包含文件名和塊索引的請求。
3、master迴應對應的chunk handle和副本的位置(多個副本)。
4、client以文件名和塊索引爲鍵緩存這些信息。(handle和副本的位置)。
5、Client 向其中一個副本發送一個請求,極可能是最近的一個副本。請求指定了chunk handle(chunkserver以chunk handle標識chunk)和塊內的一個字節區間。
6、除非緩存的信息再也不有效(cache for a limited time)或文件被從新打開,不然之後對同一個塊的讀操做再也不須要client和master間的交互。
一般Client能夠在一個請求中詢問多個chunk的地址,而master也能夠很快回應這些請求。
(5)塊規模:
塊規模是設計中的一個關鍵參數。咱們選擇的是64MB,這比通常的文件系統的塊規模要大的多。每一個塊的副本做爲一個普通的Linux文件存儲,在須要的時候能夠擴展。
塊規模較大的好處有:
1、減小client和master之間的交互。由於讀寫同一個塊只是要在開始時向master請求塊位置信息。對於讀寫大型文件這種減小尤其重要。即便對於訪問少許數據的隨機讀操做也能夠很方便的爲一個規模達幾個TB的工做集緩緩存塊位置信息。
2、Client在一個給定的塊上極可能執行多個操做,和一個chunkserver保持較長時間的TCP鏈接能夠減小網絡負載。
3、這減小了master上保存的元數據(metadata)的規模,從而使得能夠將metadata放在內存中。這又會帶來一些別的好處。
不利的一面:
一個小文件可能只包含一個塊,若是不少Client訪問改文件的話,存儲這些塊的chunkserver將成爲訪問的熱點。但在實際應用中,應用程序一般順序地讀包含多個塊的文件,因此這不是一個主要問題。
(6)元數據(metadata):
master存儲了三中類型的metadata:文件的名字空間和塊的名字空間,從文件到塊的映射,塊的副本的位置。全部的metadata都放在內存中。前兩種類型的metadata經過向操做日誌登記修改而保持不變,操做日誌存儲在master的本地磁盤並在幾個遠程機器上留有副本。使用日誌使得咱們能夠很簡單地、可靠地更新master的狀態,即便在master崩潰的狀況下也不會有不一致的問題。相反,mater在每次啓動以及當有 chuankserver加入的時候詢問每一個chunkserver的所擁有的塊的狀況。
A、內存數據結構:
由於metadata存儲在內存中,因此master的操做很快。進一步,master能夠輕易並且高效地按期在後臺掃描它的整個狀態。這種按期地掃描被用於實現塊垃圾收集、chunkserver出現故障時的副本複製、爲平衡負載和磁盤空間而進行的塊遷移。
這種方法的一個潛在的問題就是塊的數量也即整個系統的容量是否受限與master的內存。實際上,這並非一個嚴重的問題。Master爲每一個 64MB的塊維護的metadata不足64個字節。除了最後一塊,文件全部的塊都是滿的。相似的,每一個文件的名字空間數據也不足64個字節,由於文件名是以一種事先肯定的壓縮方式存儲的.若是要支持更大的文件系統,那麼增長一些內存的方法對於咱們將元數據(metadata)保存在內存種所得到的簡單性、可靠性、高性能和靈活性來講,這只是一個很小的代價。
B、塊位置:
master並不爲chunkserver所擁有的塊的副本的保存一個不變的記錄。它在啓動時經過簡單的查詢來得到這些信息。Master能夠保持這些信息的更新,由於它控制全部塊的放置並經過HeartBeat消息來監控chunkserver的狀態。
這樣作的好處:由於chunkserver可能加入或離開集羣、改變路徑名、崩潰、重啓等,一個集羣重有成百個server,這些事件常常發生,這種方法就排除了master與chunkserver之間的同步問題。
另外一個緣由是:只有chunkserver才能肯定它本身到底有哪些塊,因爲錯誤,chunkserver中的一些塊可能會很天然的消失,這樣在master中就沒有必要爲此保存一個不變的記錄。
C、操做日誌:
操做日誌包含了對metadata所做的修改的歷史記錄。它做爲邏輯時間線定義了併發操做的執行順序。文件、塊以及它們的版本號都由它們被建立時的邏輯時間而惟一地、永久地被標識。
操做日誌是如此的重要,咱們必需要將它可靠地保存起來,而且只有在metadata的改變固定下來以後纔將變化呈現給用戶。因此咱們將操做日誌複製到數個遠程的機器上,而且只有在將相應的日誌記錄寫到本地和遠程的磁盤上以後纔回答用戶的請求。
Master能夠用操做日誌來恢復它的文件系統的狀態。爲了將啓動時間減至最小,日誌就必需要比較小。每當日誌的長度增加到超過必定的規模後,master就要檢查它的狀態,它能夠從本地磁盤裝入最近的檢查點來恢復狀態。
建立一個檢查點比較費時,master的內部狀態是以一種在建立一個檢查點時並不耽誤即將到來的修改操做的方式來組織的。Master切換到一個新的日子文件並在一個單獨的線程中建立檢查點。這個新的檢查點記錄了切換前全部的修改。在一個有數十萬文件的集羣中用一分鐘左右就能完成。建立完後,將它寫入本地和遠程的磁盤。
(7)數據完整性
名字空間的修改必須是原子性的,它們只能有master處理:名字空間鎖保證了操做的原子性和正確性,而master的操做日誌在全局範圍內定義了這些操做的順序。
文件區間的狀態在修改以後依賴於修改的類型,不論操做成功仍是失敗,也不管是不是併發操做。若是不論從哪一個副本上讀,全部的客戶都看到一樣的數據,那麼文件的這個區域就是一致的。若是文件的區域是一致的而且用戶能夠看到修改操做所寫的數據,那麼它就是已定義的。若是修改是在沒有併發寫操做的影響下完成的,那麼受影響的區域是已定義的,全部的client都能看到寫的內容。成功的併發寫操做是未定義但倒是一致的。失敗的修改將使區間處於不一致的狀態。
Write操做在應用程序指定的偏移處寫入數據,而record append操做使得數據(記錄)即便在有併發修改操做的狀況下也至少原子性的被加到GFS指定的偏移處,偏移地址被返回給用戶。
在一系列成功的修改操做後,最後的修改操做保證文件區域是已定義的。GFS經過對全部的副本執行一樣順序的修改操做而且使用塊版本號檢測過期的副本(因爲chunkserver退出而致使丟失修改)來作到這一點。
由於用戶緩存了會位置信息,因此在更新緩存以前有可能從一個過期的副本中讀取數據。但這有緩存的截止時間和文件的從新打開而受到限制。
在修改操做成功後,部件故障仍能夠是數據受到破壞。GFS經過master和chunkserver間按期的handshake,藉助校驗和來檢測對數據的破壞。一旦檢測到,就從一個有效的副本儘快從新存儲。只有在GFS檢測前,全部的副本都失效,這個塊纔會丟失。
2、系統交互
(1)租約(lease)和修改順序:
(2)數據流
咱們的目標是充分利用每一個機器的網絡帶寬,避免網絡瓶頸和延遲
爲了有效的利用網絡,咱們將數據流和控制流分離。數據是以流水線的方式在選定的chunkerserver鏈上線性的傳遞的。每一個機器的整個對外帶寬都被用做傳遞數據。爲避免瓶頸,每一個機器在收到數據後,將它收到數據儘快傳遞給離它最近的機器。
(3)原子性的record Append:
GFS提供了一個原子性的添加操做:record append。在傳統的寫操做中,client指定被寫數據的偏移位置,向同一個區間的併發的寫操做是不連續的:區間有可能包含來自多個client的數據碎片。在record append中, client只是指定數據。GFS在其選定的偏移出將數據至少原子性的加入文件一次,並將偏移返回給client。
在分佈式的應用中,不一樣機器上的許多client可能會同時向一個文件執行添加操做,添加操做被頻繁使用。若是用傳統的write操做,可能須要額外的、複雜的、開銷較大的同步,例如經過分佈式鎖管理。在咱們的工做量中,這些文件一般以多個生產者單個消費者隊列的方式或包含從多個不一樣 client的綜合結果。
Record append和前面講的write操做的控制流差很少,只是在primary上多了一些邏輯判斷。首先,client將數據發送到文件最後一塊的全部副本上。而後向primary發送請求。Primary檢查添加操做是否會致使該塊超過最大的規模(64M)。若是這樣,它將該塊擴充到最大規模,並告訴其它副本作一樣的事,同時通知client該操做須要在下一個塊上從新嘗試。若是記錄知足最大規模的要求,primary就會將數據添加到它的副本上,並告訴其它的副本在在一樣的偏移處寫數據,最後primary向client報告寫操做成功。若是在任何一個副本上record append操做失敗,client將從新嘗試該操做。這時候,同一個塊的副本可能包含不一樣的數據,由於有的可能複製了所有的數據,有的可能只複製了部分。GFS不能保證全部的副本每一個字節都是同樣的。它只保證每一個數據做爲一個原子單元被寫過至少一次。這個是這樣得出的:操做要是成功,數據必須在全部的副本上的一樣的偏移處被寫過。進一步,從這之後,全部的副本至少和記錄同樣長,因此後續的記錄將被指定到更高的偏移處或者一個不一樣的塊上,即便另外一個副本成了primary。根據一致性保證,成功的record append操做的區間是已定義的。而受到干擾的區間是不一致的。
(4)快照(snapshot)
快照操做幾乎在瞬間構造一個文件和目錄樹的副本,同時將正在進行的其餘修改操做對它的影響減至最小。
咱們使用copy-on-write技術來實現snapshot。當master受到一個snapshot請求時,它首先將要snapshot的文件上塊上的lease。這使得任何一個向這些塊寫數據的操做都必須和master交互以找到擁有lease的副本。這就給master一個建立這個塊的副本的機會。
副本被撤銷或終止後,master在磁盤上登記執行的操做,而後複製源文件或目錄樹的metadata以對它的內存狀態實施登記的操做。這個新建立的snapshot文件和源文件(其metadata)指向相同的塊(chunk)。
Snapshot以後,客戶第一次向chunk c寫的時候,它發一個請求給master以找到擁有lease的副本。Master注意到chunk c的引用記數比1大,它延遲對用戶的響應,選擇一個chunk handle C’,而後要求每一有chunk c的副本的chunkserver建立一個塊C’。每一個chunkserver在本地建立chunk C’避免了網絡開銷。從這之後和對別的塊的操做沒有什麼區別。
3、MASTER操做
MASTER執行全部名字空間的操做,除此以外,他還在系統範圍管理數據塊的複製:決定數據塊的放置方案,產生新數據塊並將其備份,和其餘系統範圍的操做協同來確保數據備份的完整性,在全部的數據塊服務器之間平衡負載並收回沒有使用的存儲空間。
3.1 名字空間管理和加鎖
與傳統文件系統不一樣的是,GFS沒有與每一個目錄相關的能列出其全部文件的數據結構,它也不支持別名(unix中的硬鏈接或符號鏈接),無論是對文件或是目錄。GFS的名字空間邏輯上是從文件元數據到路徑名映射的一個查用表。
MASTER在執行某個操做前都要得到一系列鎖,例如,它要對/d1/d2…/dn/leaf執行操做,則它必須得到/d1,/d1/d2,…, /d1/d2/…/dn的讀鎖,/d1/d2…/dn/leaf的讀鎖或寫鎖(其中leaf可使文件也能夠是目錄)。MASTER操做的並行性和數據的一致性就是經過這些鎖來實現的。
3.2 備份存儲放置策略
一個GFS集羣文件系統多是多層分佈的。通常狀況下是成千上萬個文件塊服務器分佈於不一樣的機架上,而這些文件塊服務器又被分佈於不一樣機架上的客戶來訪問。所以,不一樣機架上的兩臺機器之間的通訊可能經過一個或多個交換機。數據塊冗餘配置策略要達到連個目的:最大的數據可靠性和可用性,最大的網絡帶寬利用率。所以,若是僅僅把數據的拷貝置於不一樣的機器上很難知足這兩個要求,必須在不一樣的機架上進行數據備份。這樣即便整個機架被毀或是掉線,也能確保數據的正常使用。這也使數據傳輸,尤爲是讀數據,能夠充分利用帶寬,訪問到多個機架,而寫操做,則不得不涉及到更多的機架。
3.3 產生、重複制、重平衡數據塊
當MASTER產生新的數據塊時,如何放置新數據塊,要考慮以下幾個因素:(1)儘可能放置在磁盤利用率低的數據塊服務器上,這樣,慢慢地各服務器的磁盤利用率就會達到平衡。(2)儘可能控制在一個服務器上的「新建立」的次數。(3)因爲上一小節討論的緣由,咱們須要把數據塊放置於不一樣的機架上。
MASTER在可用的數據塊備份低於用戶設定的數目時須要進行重複制。這種狀況源於多種緣由:服務器不可用,數據被破壞,磁盤被破壞,或者備份數目被修改。每一個被須要重複制的數據塊的優先級根據如下幾項肯定:第一是如今的數目距目標的距離,對於能阻塞用戶程序的數據塊,咱們也提升它的優先級。最後, MASTER按照產生數據塊的原則複製數據塊,並把它們放到不一樣的機架內的服務器上。
MASTER週期性的平衡各服務器上的負載:它檢查chunk分佈和負載平衡,經過這種方式來填充一個新的服務器而不是把其餘的內容通通放置到它上面帶來大量的寫數據。數據塊放置的原則與上面討論的相同,此外,MASTER還決定那些數據塊要被移除,原則上他會清除那些空閒空間低於平均值的那些服務器。
3.4 垃圾收集
在一個文件被刪除以後,GFS並不當即收回磁盤空間,而是等到垃圾收集程序在文件和數據塊級的的檢查中收回。
當一個文件被應用程序刪除以後,MASTER會當即記錄下這些變化,但文件所佔用的資源卻不會被當即收回,而是從新給文件命了一個隱藏的名字,並附上了刪除的時間戳。在MASTER按期檢查名字空間時,它刪除超過三天(能夠設定)的隱藏的文件。在此以前,能夠以一個新的名字來讀文件,還能夠之前的名字恢復。當隱藏的文件在名字空間中被刪除之後,它在內存中的元數據即被擦除,這就有效地切斷了他和全部數據塊的聯繫。
在一個類似的按期的名字空間檢查中,MASTER確認孤兒數據塊(不屬於任何文件)並擦除他的元數據,在和MASTER的心跳信息交換中,每一個服務器報告他所擁有的數據塊,MASTER返回元數據不在內存的數據塊,服務器便可以刪除這些數據塊。
3.5 過期數據的探測
在數據更新時若是服務器停機了,那麼他所保存的數據備份就會過期。對每一個數據塊,MASTER設置了一個版本號來區別更新過的數據塊和過期的數據塊。
當MASTER受權一個新的lease時,他會增長數據塊的版本號並會通知更新數據備份。MASTER和備份都會記錄下當前的版本號,若是一個備份當時不可用,那麼他的版本號不可能提升,當ChunkServer從新啓動並向MASTER報告他的數據塊集時,MASTER就會發現過期的數據。
MASTER在按期的垃圾收集程序中清除過期的備份,在此之前,處於效率考慮,在各客戶及英大使,他會認爲根本不存在過期的數據。做爲另外一個安全措施, MASTER在給客戶及關於數據塊的應答或是另一個讀取數據的服務器數據是都會帶上版本信息,在操做前客戶機和服務器會驗證版本信息以確保獲得的是最新的數據。
4、容錯和診斷
4.1 高可靠性
4.1.1 快速恢復
無論如何終止服務,MASTER和數據塊服務器都會在幾秒鐘內恢復狀態和運行。實際上,咱們不對正常終止和不正常終止進行區分,服務器進程都會被切斷而終止。客戶機和其餘的服務器會經歷一個小小的中斷,而後它們的特定請求超時,從新鏈接重啓的服務器,從新請求。
4.1.2 數據塊備份
如上文所討論的,每一個數據塊都會被備份到放到不一樣機架上的不一樣服務器上。對不一樣的名字空間,用戶能夠設置不一樣的備份級別。在數據塊服務器掉線或是數據被破壞時,MASTER會按照須要來複制數據塊。
4.1.3 MASTER備份
爲確保可靠性,MASTER的狀態、操做記錄和檢查點都在多臺機器上進行了備份。一個操做只有在數據塊服務器硬盤上刷新並被記錄在MASTER和其備份的上以後纔算是成功的。若是MASTER或是硬盤失敗,系統監視器會發現並經過改變域名啓動它的一個備份機,而客戶機則僅僅是使用規範的名稱來訪問,並不會發現MASTER的改變。
4.2 數據完整性
每一個數據塊服務器都利用校驗和來檢驗存儲數據的完整性。緣由:每一個服務器隨時都有發生崩潰的可能性,而且在兩個服務器間比較數據塊也是不現實的,同時,在兩臺服務器間拷貝數據並不能保證數據的一致性。
每一個Chunk按64kB的大小分紅塊,每一個塊有32位的校驗和,校驗和和日誌存儲在一塊兒,和用戶數據分開。
在讀數據時,服務器首先檢查與被讀內容相關部分的校驗和,所以,服務器不會傳播錯誤的數據。若是所檢查的內容和校驗和不符,服務器就會給數據請求者返回一個錯誤的信息,並把這個狀況報告給MASTER。客戶機就會讀其餘的服務器來獲取數據,而MASTER則會從其餘的拷貝來複制數據,等到一個新的拷貝完成時,MASTER就會通知報告錯誤的服務器刪除出錯的數據塊。
附加寫數據時的校驗和計算優化了,由於這是主要的寫操做。咱們只是更新增長部分的校驗和,即便末尾部分的校驗和數據已被損壞而咱們沒有檢查出來,新的校驗和與數據會不相符,這種衝突在下次使用時將會被檢查出來。
相反,若是是覆蓋現有數據的寫,在寫之前,咱們必須檢查第一和最後一個數據塊,而後才能執行寫操做,最後計算和記錄校驗和。若是咱們在覆蓋之前不先檢查首位數據塊,計算出的校驗和則會由於沒被覆蓋的數據而產生錯誤。
在空閒時間,服務器會檢查不活躍的數據塊的校驗和,這樣能夠檢查出不常常讀的數據的錯誤。一旦錯誤被檢查出來,服務器會拷貝一個正確的數據塊來代替錯誤的。
4.3 診斷工具
普遍而細緻的診斷日誌以微小的代價換取了在問題隔離、診斷、性能分析方面起到了重大的做用。GFS服務器用日誌來記錄顯著的事件(例如服務器停機和啓動)和遠程的應答。遠程日誌記錄機器之間的請求和應答,經過收集不一樣機器上的日誌記錄,並對它們進行分析恢復,咱們能夠完整地重現活動的場景,並用此來進行錯誤分析。
6 測量
6.1 測試環境
一臺主控機,兩臺主控機備份,16臺數據塊服務器,16臺客戶機。
每臺機器:2塊PIII1.4G處理器,2G內存,2塊80G5400rpm的硬盤,1塊100Mbps全雙工網卡
19臺服務器鏈接到一個HP2524交換機上,16臺客戶機倆接到領外一臺交換機上,兩臺交換機經過1G的鏈路相連。緩存