GFS 小結


title: GFS 小結

tags:

  • GFS
  • 分布式

categories:

  • paper
  • 分布式

comments: true
date: 2017-06-12 17:00:00


提到分布式系統,有一個無法繞開的話題—— Google 三駕馬車。本文就 GFS 概括介紹。

設計思路

與傳統的分布式系統相比,在大方向上,GFS 同樣追求高性能、高可靠性、高可用性,同時 Google 基于自身的生產環境、技術環境,有一些特殊的設計思路。

  1. 組件失效是常態化的,而非意外。在 GFS 成百上千的集群中,隨時隨地都可能發生故障導致機器宕機甚至無法恢復,所以,監控、容災、自動恢復是必須整合在 GFS 中的。

  2. 文件巨大。GB 級別的數據非常普遍,所以設計的過程中 I/O、Block 尺寸等指標應以此為參考。

  3. 絕大多數文件的寫操作都是追加(Append),而非修改(Overwrite)。通常的文件場景是順序寫,且順序讀。

  4. 應用程序 client 和 GFS API 協同設計,提高靈活性。

設計架構

GFS 架構比較簡單,一個 GFS 集群一般由一個 master 、多個 chunkserver 和多個 clients 組成,在 GFS 中,所有文件被切分成若干個 chunk,并且每個 chunk 擁有唯一不變的標識(在 chunk 創建時,由 master 負責分配),所有 chunk 都實際存儲在 chunkserver 的磁盤上。為了容災,每個 chunk 都會被復制到多個 chunkserver。
系統架構如下:


GFS 架構

在整個集群中,為了簡化設計,master 是單節點,它管理著所有文件系統的所有 metadata:命名空間、訪問控制信息、文件和 chunk 的映射關系、chunk 的存儲位置。同時 master 還管理系統范圍內的各種活動:chunk 創建、復制、遷移、回收,chunk lease 等等,是系統中最核心的部分,后面會繼續進一步描述 master 是如何工作的。

Chunkserver 真正存儲著所有 chunk,chunkserver 依托于 linux 文件系統,所以它本身不需要緩存文件數據,直接利用 linux 系統的數據緩存,簡化了設計。

Master 詳解

Master 是整個 GFS 的核心,這里重點介紹下 master 的存儲以及工作。

Metadata

所有的元數據都存儲在 Master 的內存中,以保證 Master 的性能。大部分元數據同時會以變更記錄的形式保存到操作日志中,操作日志會在本地磁盤中持久化同時被復制到其他的 Master 上(雖然是 single master,但是會有備份節點備份 Master 的相關數據,比如操作日志、checkpoint 文件,以保證可靠性)。

Master 會在后臺周期性的掃描所保存的狀態信息,因為全部在內存中,所以效率非常高。通過這種周期性的掃描,master 實現 chunk 回收、chunkserver 宕機時 chunk 的復制、以及遷移 chunk ,實現 chunkserver 的負載均衡。

但是, chunk 的位置信息不會被持久化,而是在每次 master 啟動時(以及啟動后定期執行),或有 chunkserver 加入時,master 會輪訓所有 chunkserver 獲取所有的 chunk 信息然后保存在內存中。這種方式簡化了 master 和 chunkserver 的數據同步,當然數據定期輪訓的缺點就是實時性稍差。

操作日式是元數據唯一的持久化記錄,它還定義了并發操作的執行順序的邏輯時間線,所以操作日志的完整性得到保證,才能保證 GFS 的可靠性,否則會丟失文件或者 client 的操作。因此操作日志會被復制到多臺備份節點,而且,只有 master 把操作日志持久化到本地并且復制到遠程之后,才會響應客戶端的請求,保證數據不丟失。

隨著時間的增長,操作日志會越來越大,當日止增長到一定量時,master 會將所有的系統狀態做一次 checkpoint(可以理解為持久化某一個時間點的全部狀態數據),后續的操作變更會寫入到新的日志文件,這樣在重啟或災難恢復時,master 只需要加載最新的 checkpoint 文件到內存,然后重新執行最新的一部分操作日志即可。(這也是比較通用的一種災備方法,定期做 checkpoint,然后重新記錄操作日志,恢復時基于 checkpoint + operation log)

Checkpoint 文件以壓縮 B- 樹的結構存儲,能直接映射到內存,無需額外解析,大幅提升了速度。同時創建 checkpoint 時,master 會啟動獨立的線程,不會阻塞正在進行的操作。

Operation

Master 節點執行所有的命名空間管理、chunk管理以及負責垃圾回收。

命名空間管理

Master 在操作命名空間是基于鎖實現的,在操作對應的文件或目錄時,會給對應的文件/目錄加讀鎖以及讀寫鎖,eg:對于一個 /home/usr/zhaif 的操作,會依次給父目錄 /home,/home/usr 加讀鎖,讀鎖可以防止正在讀取得文件、父目錄被刪除、改名,同時給 /home/usr/zhaif 加讀鎖或寫鎖(根據操作類型),當對操作目標的操作是修改類操作時,會加寫鎖,保證并發場景下互斥寫。

Chunk 管理

上文提到,master 會負責 chunk 副本的存儲位置,即存儲在哪些 chunkserver 上,master 會最大化的保證數據可靠性,同時最大化利用網絡帶寬。

在創建一個 chunk 時,master 選擇存儲空副本的初始位置時,會考慮一下幾點:

  1. 傾向于選擇硬盤使用率低于平均水平的 chunkserver
  2. 限制每個 chunkserver 最近一段時間的創建次數。因為創建后往往意味著后續大量的寫入。
  3. 分散在多機架

除了管理 chunk 副本的存儲位置,master 會在 chunk 有效副本數小于指定數量時重新復制 chunk 副本,以保證數據可靠性。

最后,Master 會定期對所有副本負載均衡,檢查當前副本分布情況,然后移動副本位置以更搞笑的利用硬盤空間和負載。

垃圾回收

GFS 的文件刪除不會立刻回收物理空間,而是惰性的(現如今,惰性回收在存儲系統中是一種比較常見的策略,比如 redis 回收過期數據,分配的內存空間)。這種回收機制使系統更簡單、更可靠、更高效。

當一個文件被刪除時,master 只是將文件改名,標記為已刪除。Master 會對命名空間做定期掃描,會刪除一定時間前標記刪除的文件,同時刪除其在命名空間中的記錄以及相關元數據,此時一個文件才被真正的刪除。

Master 在常規定期掃描的過程中會發現一些孤兒 chunk,即不被任何文件包含的 chunk,然后刪除他們的元數據。Chunkserver 在和 master 定期交互時,匯報了其所有的 chunk 信息,master 會告知其不存在的 chunk,chunkserver 得知后會刪除這些 chunk 副本。

這種惰性刪除的主要問題是空間利用率,尤其的在存儲空間緊缺時。所以 GFS 也提供了通過顯示的再刪除一次已經刪除的文件來加速空間回收,另外也允許用戶根據需要對不同的目錄設置不同的回收策略,eg:指定用些目錄的刪除策略為即時刪除,而不是惰性刪除。

失效副本檢測

Master 的寫操作是基于 lease 機制(后文介紹),當 master 每次分配 lease 時都會增加對應的 chunk 的版本號,然后所用最新的副本,通過版本號區分當前的和過期的副本。

讀寫操作實現

GFS 在設計是采用 client 和 API 協同設計的思路,所以在讀寫過程中 client 也不單純是發讀請求或寫請求,還包括其他一些操作。

讀實現

Client 不通過 master 節點讀寫文件,而是從 master 那獲取讀寫操作的需要聯系的 chunkserver,為了避免頻率的和 master 聯系,client 會緩存 從 master 獲取的 metadata,后續操作直接和 chunkserver 溝通實現讀寫。一次簡單的讀流程如下:

  1. Client 把要讀去的文件名和 offset,根據配置的 chunk 大小,計算出文件的 chunk 索引,然后加文件名和索引一起發送到 master,master 會返回對應 chunk 副本位置信息,client 以文件名+chunk索引作為 key 緩存此數據。

  2. 之后 client 會直接和包含此 chunk 的 chunkserver 聯系獲得文件數據。

  3. 實際上,client 一般會在一次請求中查詢多個 chunk 信息,而 master 的 response 中也一般會包含所請求 chunk 之后的一些 chunk 信息,以盡量減少 client 和 master 之間的通訊。

寫實現

相較于讀操作,寫實現更為復雜一些。所有的寫入操作會在所有 chunk 的副本上執行,GFS 采用 lease 機制來保證多個 chunk 副本之間變更順序一致。

Master 會選擇一個副本分配 lease,擁有這個 lease 的 chunk 被稱為 primary,其他副本則是 secondary。Primary 會將對 chunk 的操作序列化,然后其他 secondary 按也這個序列執行修改,從而保證所有副本變更一致。

Lease 有效期初始為 60s,primary chunk 在完成修改操作后可以申請延長 lease 有效期,同樣的 master 在一些情況下可以提起取消 lease。Master 和 chunkserver 之間會有定期的心跳監測,傳遞心跳信息是可以帶上這些 lease 的驗證請求或者批準信息。Lease 機制極大的簡化的 master 的負擔,將寫操作保證數據一致性的工作分擔給 chunkserver,使得 master 變得很輕量。

下圖是一次寫操作的流程:


寫實現
  1. Client 向 master 詢問要修改的 chunk 被哪個 chunkserver 持有 lease,以及 chunk 其他副本的位置信息。
  2. Master 返回 primary 以及 secondary 給 client。
  3. Client 把所有數據推送給 primary 和 secondary,注意這里推送的只有數據。
  4. 當所有副本都確認收到數據后,client 發送寫請求給 primary,primary 為來自不同 client 的操作分配序號,保證操作順序執行。
  5. Primary 把寫請求發送到 secondary,secondary 按照 primary 分配的序號順序執行所有操作
  6. 當 Secondary 執行完后回復 primary 執行結果。
  7. Primary 回復 client 執行結果。

GFS 將寫操作拆分為數據流(對應3)和控制流(對應4),數據流以 Pipline 的方式推送到所有副本。

原子記錄追加

GFS 同時提供了一個種原子的寫入操作——記錄追加。相比普通的寫入操作,追加只需指定要寫入的數據,不需要提供偏移量(即要寫入的位置)。GFS 會保證追加操作至少一次原子性寫入。記錄追加的控制流程同上文描述基本相同,卻別在于 primary 會檢測此次追加后 chunk 是否超過最大值,如果達到最大值,primary 會先將當前 chunk 填充滿,然后同步給 secondary 同樣操作,然后回復 client 要求其對下一個 chunk 重新執行追加操作。

原子記錄追加操作在避免了使用一個分布式鎖帶來的開銷,對于多 producer,單 consumer的場景以及合并多個來源文件的場景很契合。

一致性

GFS 是一個分布式系統,為了更好的 AP,一定程度上降低了對 C 的要求,其一致性模型是比較寬松。下圖是變更后文件狀態,其中:

  • consistent 表示所有 client 從任意副本讀取得數據相同
  • defined 表示在數據變更后,如果是 consistent,并且 client 能夠讀取到它的所有變更


    文件 region 相關操作后的狀態

從上文的寫入數據流程可以發現,串行的寫數據secondary 和 primary 操作順序是一直的,如果成功,則一定是 defined,如果失敗,則不一致,比如 primary 寫成功了,而有一個 secondary 寫失敗。同樣的道理,在并行場景下,寫失敗會不一致,但是成功的話只能保證一致,因為并發操作可能會導致一個文件 region 內包含來自多個 client 的寫操作,所以是 undefined.

記錄追加操作是原子的,GFS對于此操作能保證的是 至少一次成功 語義,所以有可能會在某個副本上發生多次追加,但是 GFS 返回給 client 的 offset 都是 defined region 的起點,如果這期間在某個副本的操作被重復追加了,此時它的 offset 會比其他大,后續的操作對所有副本都會從這個最大的 offset 開始追加,或者被追加到其他 chunk 上,因此對于記錄追加操作而言,如果執行成功,文件 region 狀態是定義的但會有部分不一致。

GFS 通過 Checksum 叫校驗數據是否損壞,比如因為宕機丟失了一些修改操作而導致失效,此時 master 會標記失效,不在返回給 client 失效的副本位置信息,并盡快回收。 對于已經被 client 緩存的失效副本信息,當 client 訪問這個失效副本時,一個失效副本會返回提前結束的 chunk,從而 client 能得知重新聯系 master 獲取最新的位置信息。

另外,正如上文所述, master 也會和 chunkserver 通過心跳來檢測宕機,并校驗數據有效性,在發現問題后會盡快恢復。

高可用性

GFS 通過快速恢復和復制保證整個集群的高可用性,無論 master 還是 chunkserver 都可以在數秒內重啟并恢復狀態。

Chunk 復制

Chunk 會被復制到不同的機架上的不同 chunkserver,當某臺 chunkserver 失效或者其上的 chunk 已損壞時,master 會繼續復制已有的副本,保證每個 chunk 的可用性。

Master 復制

Master 服務器的狀態會被復制,它所有的操作日志、checkpoint 文件都會被復制到多臺機器,對 master 服務器的狀態的任何操作都要等操作日志被復制到備份節點后本機磁盤后才會被提交生效。所以 Master 宕機后,重啟后不會有任何數據丟失,如果無法重啟或磁盤故障,則可以選擇擁有全部操作日志的備份節點啟動一個新的 master 進程。由此可以保證 master 的可靠性。

同時,還存在一些 shadow master,在 master 宕機時能可以提供 read-only 服務,但要比 master 慢一些(通常不到 1s),它們通過讀取操作日志副本的并順序執行方式保證其和 master 以相同的方式變更。同樣的,shadow master 也會和 chunkserver 定期交互檢測 chunkserver狀態、拉取數據。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 關于Mongodb的全面總結 MongoDB的內部構造《MongoDB The Definitive Guide》...
    中v中閱讀 32,012評論 2 89
  • 分布式文件系統的主要功能有兩個:一個是存儲文檔、圖像、視頻之類的Blob類型數據;另外一個是作為分布式表格系統的持...
    olostin閱讀 3,252評論 1 5
  • Google文件系統 GFS是一個可擴展的分布式文件系統,用于大型的、分布式的、對大量數據進行訪問的應用。它運行于...
    lucode閱讀 3,698評論 0 2
  • 引言 GFS是谷歌2003年提出的一個文件系統。雖然GFS比較古老,但是后來的HDFS,是受到了GFS的啟發,是G...
    炸茄盒閱讀 2,567評論 1 5
  • 五月的天頂著夏日的炎熱,還映襯著春風和暢。 碧綠的新葉遮擋驕陽,向陽花爭艷。 五月二十 只為你 為你爭艷 崢嶸花季...
    大昆_無彩閱讀 496評論 0 6