天天看點

主流分布式檔案系統選型,寫得太好了!

一、概述

分布式檔案系統是分布式領域的一個基礎應用,其中最著名的毫無疑問是 HDFS/GFS。如今該領域已經趨向于成熟,但了解它的設計要點和思想,對我們将來面臨類似場景/問題時,具有借鑒意義。

并且,分布式檔案系統并非隻有 HDFS/GFS 這一種形态,在它之外,還有其他形态各異、各有千秋的産品形态,對它們的了解,也對擴充我們的視野有所俾益。

本文試圖分析和思考,在分布式檔案系統領域,我們要解決哪些問題、有些什麼樣的方案、以及各自的選擇依據。

二、過去的樣子

在幾十年以前,分布式檔案系統就已經出現了,以 Sun 在 1984 年開發的“Network File System (NFS)”為代表,那時候解決的主要問題,是網絡形态的磁盤,把磁盤從主機中獨立出來。

這樣不僅可以獲得更大的容量,而且還可以随時切換主機,還可以實作資料共享、備份、容災等,因為資料是電腦中最重要的資産。

NFS 的資料通信圖如下:

主流分布式檔案系統選型,寫得太好了!

部署在主機上的用戶端,通過 TCP/IP 協定把檔案指令轉發到遠端檔案 Server 上執行,整個過程對主機使用者透明。

到了網際網路時代,流量和資料快速增長,分布式檔案系統所要解決的主要場景變了,開始需要非常大的磁盤空間,這在磁盤體系上垂直擴容是無法達到的,必須要分布式,同時分布式架構下,主機都是可靠性不是非常好的普通伺服器,是以容錯、高可用、持久化、伸縮性等名額,就成為必須要考量的特性。

三、對分布式檔案系統的要求

對一個分布式檔案系統而言,有一些特性是必須要滿足的,否則就無法有競争力。主要如下:

應該符合 POSIX 的檔案接口标準,使該系統易于使用,同時對于使用者的遺留系統也無需改造;

對使用者透明,能夠像使用本地檔案系統那樣直接使用;

持久化,保證資料不會丢失;

具有伸縮性,當資料壓力逐漸增長時能順利擴容;

具有可靠的安全機制,保證資料安全;

資料一緻性,隻要檔案内容不發生變化,什麼時候去讀,得到的内容應該都是一樣的。

除此之外,還有些特性是分布式加分項,具體如下:

支援的空間越大越好;

支援的并發通路請求越多越好;

性能越快越好;

硬體資源的使用率越高越合理,就越好。

四、架構模型

從業務模型和邏輯架構上,分布式檔案系統需要這幾類元件:

存儲元件:負責存儲檔案資料,它要保證檔案的持久化、副本間資料一緻、資料塊的配置設定 / 合并等等;

管理元件:負責 meta 資訊,即檔案資料的元資訊,包括檔案存放在哪台伺服器上、檔案大小、權限等,除此之外,還要負責對存儲元件的管理,包括存儲元件所在的伺服器是否正常存活、是否需要資料遷移等;

接口元件:提供接口服務給應用使用,形态包括 SDK(Java/C/C++ 等)、CLI 指令行終端、以及支援 FUSE 挂載機制。

而在部署架構上,有着“中心化”和“無中心化”兩種路線分歧,即是否把“管理元件”作為分布式檔案系統的中心管理節點。兩種路線都有很優秀的産品,下面分别介紹它們的差別。

1、有中心節點

以 GFS 為代表,中心節點負責檔案定位、維護檔案 meta 資訊、故障檢測、資料遷移等管理控制的職能,下圖是 GFS 的架構圖:

主流分布式檔案系統選型,寫得太好了!

該圖中GFS master 即為 GFS 的中心節點,GF chunkserver 為 GFS 的存儲節點。其操作路徑如下:

Client 向中心節點請求“查詢某個檔案的某部分資料”;

中心節點傳回檔案所在的位置 (哪台 chunkserver 上的哪個檔案) 以及位元組區間資訊;

Client 根據中心節點傳回的資訊,向對應的 chunk server 直接發送資料讀取的請求;

chunk server 傳回資料。

在這種方案裡,一般中心節點并不參與真正的資料讀寫,而是将檔案 meta 資訊傳回給 Client 之後,即由 Client 與資料節點直接通信。其主要目的是降低中心節點的負載,防止其成為瓶頸。這種有中心節點的方案,在各種存儲類系統中得到了廣泛應用,因為中心節點易控制、功能強大。

2、無中心節點

以ceph為代表,每個節點都是自治的、自管理的,整個 ceph 叢集隻包含一類節點,如下圖 (最下層紅色的 RADOS 就是 ceph 定義的“同時包含 meta 資料和檔案資料”的節點)。

主流分布式檔案系統選型,寫得太好了!

無中心化的最大優點是解決了中心節點自身的瓶頸,這也就是 ceph 号稱可以無限向上擴容的原因。但由 Client 直接和 Server 通信,那麼 Client 必須要知道,當對某個檔案進行操作時,它該通路叢集中的哪個節點。ceph 提供了一個很強大的原創算法來解決這個問題——CRUSH 算法。

五、持久化

對于檔案系統來說,持久化是根本,隻要 Client 收到了 Server 儲存成功的回應之後,資料就不應該丢失。這主要是通過多副本的方式來解決,但在分布式環境下,多副本有這幾個問題要面對。

如何保證每個副本的資料是一緻的?

如何分散副本,以使災難發生時,不至于所有副本都被損壞?

怎麼檢測被損壞或資料過期的副本,以及如何處理?

該傳回哪個副本給 Client?

1、如何保證每個副本的資料是一緻的?

同步寫入是保證副本資料一緻的最直接的辦法。當 Client 寫入一個檔案的時候,Server 會等待所有副本都被成功寫入,再傳回給 Client。

這種方式簡單、有保障,唯一的缺陷就是性能會受到影響。假設有 3 個副本,如果每個副本需要N秒,則可能會阻塞 Client 3N 秒的時間,有幾種方式,可以對其進行優化:

并行寫:由一個副本作為主副本,并行發送資料給其他副本;

鍊式寫:幾個副本組成一個鍊 (chain),并不是等内容都接受到了再往後傳播,而是像流一樣,邊接收上遊傳遞過來的資料,一邊傳遞給下遊。

還有一種方式是采用 CAP 中所說的 W+R>N 的方式,比如 3 副本 (N=3) 的情況,W=2,R=2,即成功寫入 2 個就認為成功,讀的時候也要從 2 個副本中讀。這種方式通過犧牲一定的讀成本,來降低寫成本,同時增加寫入的可用性。這種方式在分布式檔案系統中用地比較少。

2、如何分散副本,以使災難發生時,不至于所有副本都被損壞?

這主要避免的是某機房或某城市發生自然環境故障的情況,是以有一個副本應該配置設定地比較遠。它的副作用是會帶來這個副本的寫入性能可能會有一定的下降,因為它離 Client 最遠。是以如果在實體條件上無法保證夠用的網絡帶寬的話,則讀寫副本的政策上需要做一定考慮。

可以參考同步寫入隻寫 2 副本、較遠副本異步寫入的方式,同時為了保證一緻性,讀取的時候又要注意一些,避免讀取到異步寫入副本的過時資料。

3、怎麼檢測被損壞或資料過期的副本,以及如何處理?

如果有中心節點,則資料節點定期和中心節點進行通信,彙報自己的資料塊的相關資訊,中心節點将其與自己維護的資訊進行對比。如果某個資料塊的 checksum 不對,則表明該資料塊被損壞了;如果某個資料塊的 version 不對,則表明該資料塊過期了。

如果沒有中心節點,以 ceph 為例,它在自己的節點叢集中維護了一個比較小的 monitor 叢集,資料節點向這個 monitor 叢集彙報自己的情況,由其來判定是否被損壞或過期。

當發現被損壞或過期副本,将它從 meta 資訊中移除,再重新建立一份新的副本就好了,移除的副本在随後的回收機制中會被收回。

4、該傳回哪個副本給 Client?

這裡的政策就比較多了,比如 round-robin、速度最快的節點、成功率最高的節點、CPU 資源最空閑的節點、甚至就固定選第一個作為主節點,也可以選擇離自己最近的一個,這樣對整體的操作完成時間會有一定節約。

六、伸縮性

1、存儲節點的伸縮

當在叢集中加入一台新的存儲節點,則它主動向中心節點注冊,提供自己的資訊,當後續有建立檔案或者給已有檔案增加資料塊的時候,中心節點就可以配置設定到這台新節點了,比較簡單。但有一些問題需要考慮。

如何盡量使各存儲節點的負載相對均衡?

怎樣保證新加入的節點,不會因短期負載壓力過大而崩塌?

如果需要資料遷移,那如何使其對業務層透明?

1)如何盡量使各存儲節點的負載相對均衡?

首先要有評價存儲節點負載的名額。有多種方式,可以從磁盤空間使用率考慮,也可以從磁盤使用率 +CPU 使用情況 + 網絡流量情況等做綜合判斷。一般來說,磁盤使用率是核心名額。

其次在配置設定新空間的時候,優先選擇資源使用率小的存儲節點;而對已存在的存儲節點,如果負載已經過載、或者資源使用情況不均衡,則需要做資料遷移。

2)怎樣保證新加入的節點,不會因短期負載壓力過大而崩塌?

當系統發現目前新加入了一台存儲節點,顯然它的資源使用率是最低的,那麼所有的寫流量都路由到這台存儲節點來,那就可能造成這台新節點短期負載過大。是以,在資源配置設定的時候,需要有預熱時間,在一個時間段内,緩慢地将寫壓力路由過來,直到達成新的均衡。

3)如果需要資料遷移,那如何使其對業務層透明?

在有中心節點的情況下,這個工作比較好做,中心節點就包辦了——判斷哪台存儲節點壓力較大,判斷把哪些檔案遷移到何處,更新自己的 meta 資訊,遷移過程中的寫入怎麼辦,發生重命名怎麼辦。無需上層應用來處理。

如果沒有中心節點,那代價比較大,在系統的整體設計上,也是要考慮到這種情況,比如ceph,它要采取邏輯位置和實體位置兩層結構,對Client暴露的是邏輯層 (pool 和 place group),這個在遷移過程中是不變的,而下層實體層資料塊的移動,隻是邏輯層所引用的實體塊的位址發生了變化,在Client看來,邏輯塊的位置并不會發生改變。

2、中心節點的伸縮

如果有中心節點,還要考慮它的伸縮性。由于中心節點作為控制中心,是主從模式,那麼在伸縮性上就受到比較大的限制,是有上限的,不能超過單台實體機的規模。我們可以考慮各種手段,盡量地擡高這個上限。有幾種方式可以考慮:

以大資料塊的形式來存儲檔案——比如 HDFS 的資料塊的大小是 64M,ceph 的的資料塊的大小是 4M,都遠遠超過單機檔案系統的 4k。它的意義在于大幅減少 meta data 的數量,使中心節點的單機記憶體就能夠支援足夠多的磁盤空間 meta 資訊。

中心節點采取多級的方式——頂級中心節點隻存儲目錄的 meta data,其指定某目錄的檔案去哪台次級總控節點去找,然後再通過該次級總控節點找到檔案真正的存儲節點;

中心節點共享儲存設備——部署多台中心節點,但它們共享同一個存儲外設 / 資料庫,meta 資訊都放在這裡,中心節點自身是無狀态的。這種模式下,中心節點的請求處理能力大為增強,但性能會受一定影響。iRODS 就是采用這種方式。

七、高可用性

1、中心節點的高可用

中心節點的高可用,不僅要保證自身應用的高可用,還得保證 meta data 的資料高可用。

meta data 的高可用主要是資料持久化,并且需要備份機制保證不丢。一般方法是增加一個從節點,主節點的資料實時同步到從節點上。也有采用共享磁盤,通過 raid1 的硬體資源來保障高可用。顯然增加從節點的主備方式更易于部署。

meta data 的資料持久化政策有以下幾種方式:

直接儲存到存儲引擎上,一般是資料庫。直接以檔案形式儲存到磁盤上,也不是不可以,但因為 meta 資訊是結構化資料,這樣相當于自己研發出一套小型資料庫來,複雜化了。

儲存日志資料到磁盤檔案 (類似 MySQL 的 binlog 或 Redis 的 aof),系統啟動時在記憶體中重建成結果資料,提供服務。修改時先修改磁盤日志檔案,然後更新記憶體資料。這種方式簡單易用。

目前記憶體服務 + 日志檔案持久化是主流方式。一是純記憶體操作,效率很高,日志檔案的寫也是順序寫;二是不依賴外部元件,獨立部署。

為了解決日志檔案會随着時間增長越來越大的問題,以讓系統能以盡快啟動和恢複,需要輔助以記憶體快照的方式——定期将記憶體 dump 儲存,隻保留在 dump 時刻之後的日志檔案。這樣當恢複時,從最新一次的記憶體 dump 檔案開始,找其對應的 checkpoint 之後的日志檔案開始重播。

2、存儲節點的高可用

在前面“持久化”章節,在保證資料副本不丢失的情況下,也就保證了其的高可用性。

八、性能優化和緩存一緻性

這些年随着基礎設施的發展,區域網路内千兆甚至萬兆的帶寬已經比較普遍,以萬兆計算,每秒傳輸大約 1250M 位元組的資料,而 SATA 磁盤的讀寫速度這些年基本達到瓶頸,在 300-500M/s 附近,也就是純讀寫的話,網絡已經超過了磁盤的能力,不再是瓶頸了,像 NAS 網絡磁盤這些年也開始普及起來。

但這并不代表,沒有必要對讀寫進行優化,畢竟網絡讀寫的速度還是遠慢于記憶體的讀寫。常見的優化方法主要有:

記憶體中緩存檔案内容;

預加載資料塊,以避免用戶端等待;

合并讀寫請求,也就是将單次請求做些積累,以批量方式發送給 Server 端。

緩存的使用在提高讀寫性能的同時,也會帶來資料不一緻的問題:

會出現更新丢失的現象。當多個 Client 在一個時間段内,先後寫入同一個檔案時,先寫入的 Client 可能會丢失其寫入内容,因為可能會被後寫入的 Client 的内容覆寫掉;

資料可見性問題。Client 讀取的是自己的緩存,在其過期之前,如果别的 Client 更新了檔案内容,它是看不到的;也就是說,在同一時間,不同 Client 讀取同一個檔案,内容可能不一緻。

這類問題有幾種方法:

檔案隻讀不改:一旦檔案被 create 了,就隻能讀不能修改。這樣 Client 端的緩存,就不存在不一緻的問題;

通過鎖:用鎖的話還要考慮不同的粒度。寫的時候是否允許其他 Client 讀? 讀的時候是否允許其他 Client 寫? 這是在性能和一緻性之間的權衡,作為檔案系統來說,由于對業務并沒有限制性,是以要做出合理的權衡,比較困難,是以最好是提供不同粒度的鎖,由業務端來選擇。但這樣的副作用是,業務端的使用成本擡高了。

九、安全性

由于分布式檔案存儲系統,肯定是一個多用戶端使用、多租戶的一個産品,而它又存儲了可能是很重要的資訊,是以安全性是它的重要部分。

主流檔案系統的權限模型有以下這麼幾種:

DAC:全稱是 Discretionary Access Control,就是我們熟悉的 Unix 類權限架構,以 user-group-privilege 為三級體系,其中 user 就是 owner,group 包括 owner 所在 group 和非 owner 所在的 group、privilege 有 read、write 和 execute。這套體系主要是以 owner 為出發點,owner 允許誰對哪些檔案具有什麼樣的權限。

MAC:全稱是 Mandatory Access Control,它是從資源的機密程度來劃分。比如分為“普通”、“機密”、“絕密”這三層,每個使用者可能對應不同的機密閱讀權限。這種權限體系起源于安全機構或軍隊的系統中,會比較常見。它的權限是由管理者來控制和設定的。Linux 中的 SELinux 就是 MAC 的一種實作,為了彌補 DAC 的缺陷和安全風險而提供出來。關于 SELinux 所解決的問題可以參考 What is SELinux?

RBAC:全稱是 Role Based Access Control,是基于角色 (role) 建立的權限體系。角色擁有什麼樣的資源權限,使用者歸到哪個角色,這對應企業 / 公司的組織機構非常合适。RBAC 也可以具體化,就演變成 DAC 或 MAC 的權限模型。

市面上的分布式檔案系統有不同的選擇,像 ceph 就提供了類似 DAC 但又略有差別的權限體系,Hadoop 自身就是依賴于作業系統的權限架構,同時其生态圈内有 Apache Sentry 提供了基于 RBAC 的權限體系來做補充。

十、其他

1、空間配置設定

有連續空間和連結清單空間兩種。連續空間的優勢是讀寫快,按順序即可,劣勢是造成磁盤碎片,更麻煩的是,随着連續的大塊磁盤空間被配置設定滿而必須尋找空洞時,連續配置設定需要提前知道待寫入檔案的大小,以便找到合适大小的空間,而待寫入檔案的大小,往往又是無法提前知道的 (比如可編輯的 word 文檔,它的内容可以随時增大);

而連結清單空間的優勢是磁盤碎片很少,劣勢是讀寫很慢,尤其是随機讀,要從連結清單首個檔案塊一個一個地往下找。

為了解決這個問題,出現了索引表——把檔案和資料塊的對應關系也儲存一份,存在索引節點中 (一般稱為 i 節點),作業系統會将 i 節點加載到記憶體,進而程式随機尋找資料塊時,在記憶體中就可以完成了。通過這種方式來解決磁盤連結清單的劣勢,如果索引節點的内容太大,導緻記憶體無法加載,還有可能形成多級索引結構。

2、檔案删除

實時删除還是延時删除? 實時删除的優勢是可以快速釋放磁盤空間;延時删除隻是在删除動作執行的時候,置個辨別位,後續在某個時間點再來批量删除,它的優勢是檔案仍然可以階段性地保留,最大程度地避免了誤删除,缺點是磁盤空間仍然被占着。在分布式檔案系統中,磁盤空間都是比較充裕的資源,是以幾乎都采用邏輯删除,以對資料可以進行恢複,同時在一段時間之後 (可能是 2 天或 3 天,這參數一般都可配置),再對被删除的資源進行回收。

怎麼回收被删除或無用的資料? 可以從檔案的 meta 資訊出發——如果 meta 資訊的“檔案 - 資料塊”映射表中包含了某個資料塊,則它就是有用的;如果不包含,則表明該資料塊已經是無效的了。是以,删除檔案,其實是删除 meta 中的“檔案 - 資料塊”映射資訊 (如果要保留一段時間,則是把這映射資訊移到另外一個地方去)。

3、面向小檔案的分布式檔案系統

有很多這樣的場景,比如電商——那麼多的商品圖檔、個人頭像,比如社交網站——那麼多的照片,它們具有的特性,可以簡單歸納下:

每個檔案都不大;

數量特别巨大;

讀多寫少;

不會修改。

針對這種業務場景,主流的實作方式是仍然是以大資料塊的形式存儲,小檔案以邏輯存儲的方式存在,即檔案 meta 資訊記錄其是在哪個大資料塊上,以及在該資料塊上的 offset 和 length 是多少,形成一個邏輯上的獨立檔案。這樣既複用了大資料塊系統的優勢和技術積累,又減少了 meta 資訊。

4、檔案指紋和去重

檔案指紋就是根據檔案内容,經過算法,計算出檔案的唯一辨別。如果兩個檔案的指紋相同,則檔案内容相同。在使用網絡雲盤的時候,發現有時候上傳檔案非常地快,就是檔案指紋發揮作用。雲盤服務商通過判斷該檔案的指紋,發現之前已經有人上傳過了,則不需要真的上傳該檔案,隻要增加一個引用即可。在檔案系統中,通過檔案指紋可以用來去重、也可以用來判斷檔案内容是否損壞、或者對比檔案副本内容是否一緻,是一個基礎元件。

檔案指紋的算法也比較多,有熟悉的 md5、sha256、也有 google 專門針對文本領域的 simhash 和 minhash 等。

十一、總結

分布式檔案系統内容龐雜,要考慮的問題遠不止上面所說的這些,其具體實作也更為複雜。本文隻是盡量從分布式檔案系統所要考慮的問題出發,給予一個簡要的分析和設計,如果将來遇到類似的場景需要解決,可以想到“有這種解決方案”,然後再來深入研究。

同時,市面上也是存在多種分布式檔案系統的形态,下面就是有研究小組曾經對常見的幾種分布式檔案系統的設計比較。

主流分布式檔案系統選型,寫得太好了!

從這裡也可以看到,選擇其實很多,并不是 GFS 論文中的方式就是最好的。在不同的業務場景中,也可以有更多的選擇政策。