分布式存儲系統: GFS


一. 簡介

  2003 年 谷歌在第19屆ACM操作系統原理研討會(Symposium on Operating Systems Principles,SOSP)上,發表了論文《Google文件系統》,系統地介紹了Google面向大規模數據密集型應用的、可伸縮的分布式文件系統——GFS。
  GFS是一個可擴展的大型數據密集型應用的分布式文件系統,該文件系統可在廉價的硬件上運行,並具有可靠的容錯能力,該文件系統可為用戶提供極高的計算性能,而同時具備最小的硬件投資和運營成本。

  在如今看來 GFS 依舊是一個可用的分布式存儲系統,Taobao File SystemFacebook Haystack這兩個存儲系統就與 GFS 的結構類似,不過他們都優化了對小文件的支持,這部分 GFS 是沒有的.

二. GFS 設計概要

1. 設計預期

  任何系統都只能解決特定場景的特定問題.所以在討論一個系統時應該明確該系統是為了解決什么問題,為這個問題付出了什么代價,做出了那些取舍.對 GFS 來說,有以下假設或限制

  • 系統由許多廉價的設備組成, 所以系統要冗余和修復錯誤節點/組件.
  • 系統存儲大量(百萬)大文件(100MB 以上),可以存儲小文件但是沒有優化.
  • 系統支持兩種類型讀操作:大量的順序讀取以及小規模的隨機讀取.
  • 系統高效、語義明確地支持多路並行追加數據到同一文件.
  • 系統的寫操作主要為大規模的、順序的、數據追加方式的.
  • 系統更看重平均響應時間,而不是單次的.

2. GFS 架構

  一個 GFS 集群包含一個單獨的 Master 節點(有備份),多台 Chunk Server, 同時被多台 Client 訪問.

   GFS 存儲的文件都被分割成多個固定大小(64MB, 文件的最后一個 Chunk 允許不足 64MB)的 Chunk.每個 Chunk都一個唯一的 64 位 Chunk id.Chunk 服務器把 Chunk 以 Linux 文件的形式保存在本地磁盤上,並根據指定的 Chunk id 和 Range 來讀寫塊數據.為防止數據丟失,默認使用 3 副本冗余, 不過也可以自己創建 namespace 指定不同的冗余策略.

   Master 節點是元數據服務器.包括 namespace, 文件和 Chunk 的映射信息, Chunk 位置信息.前兩者持久化在系統磁盤.Chunk 位置信息在每次啟動時從 Chunk Server獲取並一直實時更新.
   Master 節點還管理系統內的調度,比如 Chunk Lease 管理,垃圾回收, Chunk 遷移等.Chunk Server 向 Master 發送心跳.

  Client 代碼以庫的形式鏈接到用戶代碼中.Client 只從 Master 獲取元數據,以此直接和 Chunk Server 通信.

  Client 和 Chunk Server 都無需緩存文件數據.我們大部分時候都是流式讀取一個巨大文件,或者工作集太大無法緩存,很少小范圍內隨機多次訪問.並且放棄緩存也會簡化系統的設計與實現.並且 Linux 系統會將經常訪問的數據緩存在內存中.

3. 單一 Master 節點

  單一 Master 節點 結構簡單. 單一 Master 節點進行Chunk 管理時很精准.Master 節點避免直接讀寫文件,應該只是作為元數據服務器.下面描述一次讀操作:

  • Client 根據文件名和偏移量和 Chunk 固定的 Size 計算出 Chunk 索引
  • Client 將文件名和 Chunk 索引發送到 Master(可以一次請求多個Chunk)
  • Master 將對應的 Chunk id 和 副本位置信息發還給客戶端
  • Client 就近選擇一個副本處進行讀操作.

4. Chunk 尺寸

  Chunk 大小選擇了固定的 64MB, 這個大小在2003看來很大,但在如今就感覺蠻合適.當時主要考慮的是:

  • 減少了Master 節點和 Client 的通訊需求.一次請求可以覆蓋大范圍的文件
  • Client 也可以輕松的緩存數 TB 的工作數據的 Chunk 元數據
  • 減少了 Master 元數據需要保存的數量
  • Client 可以和 Chunk Server 一次 TCP 連接可以保持較長時間

6. 一致性模型

  GFS 使用單一 Master 節點和 Lease 機制來保證分布式操作下語義正確,從而保證副本內各節點的一致性.同時 Chunk Server定時向 Master 發送心跳,Master 可以及時的進行垃圾回收和 Chunk 遷移,保證副本內各節點的一致性.

三. 詳細設計

1. Master 服務器的復制

  上文說到 GFS 集群中只有一個 Master 節點,這個一個是邏輯上的一個.實際上有多台機器(只保存操作日志和快照,不啟動 Master 實例)來保障 GFS 集群的可靠性.Master 服務器的操作日志和 checkpoint文件會被復制到其他備用機器上,並且所有操作都是同步的,即 Master 和 所有備份機器操作日志和 checkpoint都寫成功這次修改才能夠提交成功.

  Master 的故障轉移由外部的監控程序進行,當提供 Master 服務的節點發生錯誤且不能恢復,由外部監控程序在Master 備份節點上啟動新的 Master 進程並快速恢復服務(Chunk 位置信息會主動向所有 Chunk Server 獲取一次,其他信息操作日志和 checkpoint 中有).同時客戶端規范使用類似DNS 的操作將 Master 的地址改為最新的.

   GFS 中還有一些 Master 服務器的副本(影子),當 Master 服務器宕機時提供只讀操作.不過影子 Master 服務器更新是異步的,也就是 Master 和影子 Master 可能會有短暫的不一致發生.

   Master 在宕機時集群會短暫停止寫服務,不過仍然可以提供讀服務.Master 會在短暫時間間隔內恢復

2. lease 和 寫 Chunk 流程

  為了保證 Chunk 與其副本在並發修改下保持一致,GFS 使用了 Lease 機制, 簡單描述就是一個全局資源鎖, Client 需要 Master 保證在一段時間內當前 Chunk 不會有未知的變化(例如被其他人修改),具體可見Lease 機制

   注意:應該在熟悉 Lease 機制后再閱讀寫流程內容.寫流程如下:

  1. Client 向 Master 節點詢問哪一個 Chunk Server持有指定 Chunk的 Lease以及其他副本的位置,如果沒有就選擇其中一個副本建一個 Lease
  2. Master 節點將主 Chunk 的標識符以及其他副本的位置返回給 Client,Client 緩存這些數據.
    • 只有主 Chunk 不可用或主 Chunk 表明其不持有 Lease,Client 才需要重新跟 Master 節點聯系.
  3. Client 把數據推送到所有副本上.
    • Client可以以任意的順序推送數據
    • Chunk Server 收到數據並保存在它的內部 LRU 緩存中
  4. 當所有的副本都確認接收到了數據,客戶機發送寫請求到主 Chunk 服務器
    • 這個寫請求標識了早前所有推送到副本上的數據
    • 主 Chunk 為接收到的所有操作分配連續的序列號,並順序執行這些操作,來更新自己(這個 Chunk)
  5. 主 Chunk 把寫請傳遞到所有的二級副本上.每個二級副本依照主 Chunk 分配的序列號以相同的順序執行這些操作.
  6. 所有的二級副本回復主 Chunk.
  7. 主 Chunk 服務器回復客戶機.
    • 任何副本產生的任何錯誤都會返回給 Client
    • 客戶端通過重復執行失敗的操作來處理錯誤

注意: 對多個 Chunk 的寫操作會將其分割成獨立的,也就是以 Chunk 為單位進行寫操作

3. 數據流動

  為了提高效率, GFS 將數據流和控制流分開.控制流就是寫流程中除第 3 步外的所有.數據流采取了一種特殊的方法進行推送,目標
是充分利用每台機器的帶寬,避免網絡瓶頸和高延時的連接,最小化推送所有數據的延時。

   GFS 采用鏈式傳輸數據,如下圖所示,數據流不會直接傳輸所有到目標機器,而是按照距離遠近以鏈式方式傳輸.

  所有 Chunk Server 使用基於 TCP 連接的、管道式數據推送方式來最小化延遲.接收到數據后立刻向前推送不會降低接收的速度.在沒有網絡擁塞的情況下,傳送 B 個字節的數據到 N 個副本的理想時間是 B/T + RL, T 是網速,L 是在兩台機器數據傳輸的延遲.通常情況下,我們的網速為 100Mbps,L 將遠小於 1ms,因此 1GB 的數據在理想情況下 80ms 左右就能分發出去,而使用主從模式耗時會隨副本數量線性增長.

4. Chunk 位置選擇

副本位置選擇在任何存儲系統中都是非常重要的事情, Ceph 的 Crush, 一致性 hash都是解決這個問題的常用方法.

  Chunk 副本位置選擇的策略服務兩大目標:最大化數據可靠性和可用性, 最大化網絡帶寬利用率.為了實現這個目標,僅僅是在多台機器上分別存儲這些副本是不夠的,這只能預防硬盤損壞或者機器失效帶來的影響,以及最大化每台機器的網絡帶寬利用率。我們必須在多個機架間分布儲存Chunk的副本。這保證Chunk的一些副本在整個機架被破壞或掉線(比如,共享資源,如電源或者網絡交換機造成的問題)的情況下依然存在且保持可用狀態。這還意味着在網絡流量方面,尤其是針對 Chunk 的讀操作,能夠有效利用多個機架的整合帶寬。另一方面,寫操作必須和多個機架上的設備進行網絡通信,但是這個代價是我們願意付出的。

Chunk 位置選擇發生在三種場景下:Chunk 創建, 重新復制和重新負載均衡.

a. Chunk 創建

當 Master 節點創建一個 Chunk 時會考慮幾個因素:

  1. 希望在低於平均磁盤使用率的 Chunk 服務器上存儲新的副本.這樣可以平衡 Chunk Server 之間的磁盤使用率.
  2. 希望限制在每個 Chunk Server 上"最近"的 Chunk 創建操作的次數,更加平均的在所有Chunk Server 上創建新 Chunk.因為在絕大多數為追加的工作模式下,Chunk 創建成功幾乎成為只讀的了.
  3. 希望將 Chunk 的副本分布在多個機架之間.甚至機房或 IDC.這樣既能提高數據可靠性,同時消除了單個機架對網絡的限制.

  具體的實現論文中沒有描述, 不過由於有中心化的 Master 節點所以任何實現方法都是可用的.而不用考慮 Crush 或一致性 hash.這兩種是在不同實現下的不同選擇

b. Chunk 復制

  當 Chunk 的有效副本數量少於指定數量時,Master 節點會重新復制它(這個信息會在 Master 啟動時由 Chunk Server 上報,並由單一 Master 節點和 Chunk Server 心跳來保持是最新). 有以下的原因:

  1. Chunk Server 不可用
  2. Chunk Server 報告它存儲的一個副本損壞了
  3. Chunk Server 的磁盤錯誤不可用
  4. Chunk 副本數量提升了.

  Chunk 復制的策略和創建操作類似, 優先選擇優先級最高的 Chunk(丟失副本數量更多或被訪問的更頻繁的 Chunk),選擇策略如下:

  1. 平衡硬盤使用率
  2. 限制同一台 Chunk Server 上正在進行的克隆操作的數量
  3. 在機架間分布副本
  4. 限制整體復制操作的數量以此保證不會對正常服務造成影響

c. Chunk 重新負載均衡

  Master 會周期性的對副本進行重新負載均衡: 它檢查當前的副本分布情況,然后移動副本以便更好的利用磁盤空間,更有效的進行負載均衡.

  由於GFS 有中心化的 Master 節點,所以任何Chunk 的遷移都不會對正常服務造成影響,同時 Chunk 管理策略的變更也不會對現有服務造成影響.

5. Namespace 和鎖

   使用 Namespace 可以將很多互斥的操作隔離,在保證安全性的同時提高並發.

  不同於許多傳統文件系統,GFS 的 namespace 就是一個全路徑和元數據映射關系的查找表。利用前綴壓縮,這個表可以高效的存儲在內存中。在存儲名稱空間的樹型結構上,每個節點(絕對路徑的文件名或絕對路徑的目錄名)都有一個關聯的讀寫鎖。對一個節點進行寫操作時首先會獲取上級節點的讀鎖以及本節點的讀寫鎖,這樣就可以支持對同一目錄的並行目錄.

  因為名稱空間可能有很多節點,讀寫鎖采用惰性分配策略,在不再使用的時候立刻被刪除。同樣,鎖的獲取也要依據一個全局一致的順序來避免死鎖:首先按名稱空間的層次排序,在同一個層次內按字典順序排序。

總結

  GFS 是經典且經歷近 20 年仍不過時的一個大文件分布式存儲系統, 在 Google File System 對 GFS 的設計大概和細節都有詳細的描述,本文只選擇了一些重點和自己感興趣的地方進行了記錄.我認為深入學習一下 GFS 是有積極意義的.同時還有一些章節在本文中沒有體現,在接下來的學習工作生涯中遇到相似的問題會繼續在本文中更新.限於本文的作者水平,文中的錯誤在所難免,懇請大家批評指正.

  在 3.3 節的數據流動中, 經過計算讓我對鏈式傳輸和主從傳輸有了更深入的認識,也許計算機中計算才是最重要的.

引用

  1. google: The Google File System
  2. xybaby: 典型分布式系統分析: GFS


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM