1. 程式人生 > >Ceph:一種可擴充套件,高效能的分散式檔案系統

Ceph:一種可擴充套件,高效能的分散式檔案系統

摘要

我們開發了 Ceph,一種分散式檔案系統。該檔案系統提供極佳的效能,可靠性以及擴充套件性。通過專為不可靠的物件儲存裝置(Object Storage Device,OSDs)所組成的異構、動態叢集而設計的準隨機資料分配演算法(CRUSH),利用其替代檔案分配表,Ceph 將資料與元資料進行了最大程度地分離。通過將資料分佈,失效檢測恢復指定給執行特殊本地物件檔案系統的半自動化的OSDs的方式來使裝置具備智慧性。而動態的分散式元資料叢集,為各種通用目以及科學計算檔案系統工作負載提供了無逢自適應,且高效的元資料管理。經測評,在各種工作負載中,Ceph 都表現出了相當出色的 I/O 效能以及可擴充套件元資料管理,並且支援多達每秒250,000次的元資料操作。

1 介紹

在各種應用中,檔案系統的總體效能都是非常關鍵的。因此長期以來,系統設計者一直在竭力尋求提高檔案系統性的方法。分散式檔案系統的效能以及擴充套件性一直受到科學與高效能運算的驅動,而最近這幾年,通用目的的系統也要求檔案系統的具備高效能與擴充套件性。傳統的解決方案,像 NFS 提供一種直接的模式,即伺服器輸出一個檔案系統,客戶端即可將其目錄結構影射到本地檔案系統中。雖然使用廣泛,但是這種集中式的C/S結構對於效能的提高是一個巨大的障礙。

許多最近的分散式檔案系統都採用基於物件檔案的系統架構,在這個構架下傳統的磁碟由 OSDs 替換。一個 OSD 是由 CPU、網路介面、本地磁碟或者 RAID 所組成。比之於傳統磁碟,在 OSDs 上,客戶端可以讀寫位元組數大得多有名物件(通常大小是不固定的),並且將底層資料分配責任分發給裝置自己(OSD)。典型地,客戶端只與元資料伺服器互動(MDs)來執行元資料操作,直接與 OSDs 通訊來執行檔案的 I/O,通過這樣方式顯著地提高了系統的可擴充套件性。但是這種模式還會受到擴充套件性的限制,因為元資料負載要麼很少甚至不是分佈的。傳統檔案系統規範,如分配列表、inode 表以及代理 OSDs 本身的責任,會進一步限制可擴充套件性與效能,並且增加可靠性維護的代價。

我們引入 Ceph 這樣的分散式檔案系統,其能提供極佳的效能、可靠性,同時又有無可比擬的可擴充套件性。我們的構架設計是基於在 PB 級別的系統客戶所具有的動態特性假設,即大系統總是增量搭建的,並且結點的失效是常規事件而不是異常事件,負載量與負載特點總是隨時間不斷變化。

Ceph 通過用產生函式來替換檔案分配表的方式,將資料與元資料操作解藕。這使得 Ceph 能夠使 OSDs 具備智慧性,因此可以將訪問資料、更新序列化、複製及可靠性,失效檢測與恢復等的複雜性分散到 OSDs 裝置上。利用高度可配接的分散式元資料叢集架構極大地提高了元資料訪問的可擴充套件性,並藉此提高了整個系統的可擴充套件性。我們探討推進我們在系統構架設計之初的目標與負載特性的討論、分析它們對於系統及效能的影響,並結合我們的經驗,從而來實現功能系統的原型。

圖 1:系統構架。客戶端與OSD直接通訊並執行檔案I/O。每個程序都可以直接與客戶端例項連線,或者與已經掛載的檔案系統進行互動。

2 系統概述

Ceph 有三個主要元件:客戶端,用於向程序及主機暴露一個“類-Posix”檔案系統介面;一組 OSDs,用來收集並存儲所有的資料以及元資料;元資料伺服器叢集,來用管理名字空間(檔名以及目錄),並處理安全,一致性以及相關性(見圖1)。我們說 Ceph 是“類-Posix”是因為,為了符合應用要求並提高系統性能,我們擴充套件了介面,並且有選擇地放寬了一致性語義。

Ceph架構的主要目標是可擴充套件性(即能擴充套件到數百Petabytes 或者更多)以及效能與可靠性。擴充套件性可從多個維度來考慮,包括全域性儲存能力以及系統的吞吐量,以及單個客戶端、目錄、檔案的效能。我們的目標負載包括這樣的極端場景:即成百上千個主機同時併發讀寫相同檔案,或者在同一個目錄建立檔案。此類場景在超級計算叢集的科學應用中相當普遍,並且在未來的通用目的的工作負載中也有出現的跡象。更重要的是,我們認識到分散式檔案系統的負載是動態的,因為做為活躍應用,對於資料與元資料的訪問以及資料集本身都是隨時間不斷變化的。Ceph 通過三個方面的特性設計,在直接解決了擴充套件性的同時,取得了高效能、可擴充套件性及可用性。這三個特性為解藕資料與元資料的訪問,動態分散式元資料管理,以及可靠的自動分散式物件儲存。

解藕資料以及元資料——Ceph 最大化地分離了與檔案資料儲存與元資料管理。元資料操作(開啟,改名等)統一地由元資料叢集伺服器管理,而客戶端則直接與 ODSs 通訊來執行檔案的 I/O(讀與寫)。因為代理了底層塊裝置的分配決策,因此基於物件的檔案系統能夠提高檔案系統的可擴充套件性。但是另一方面,現有的基於對像的檔案系統[4,7,8,32]只是通過將長的單檔案分配塊列表替換為短的分配塊列表。而 Ceph 則是完全取消了分配列表。另外,檔案資料利用專有資料分配函式,被分片到可計算的具名物件後儲存到儲存裝置上。這使得任何部分都可以通過計算(而不是查詢)得到檔名以及組成檔案的物件的位置,而不是需要維護檔案物件的列表,簡化了系統的設計,減少了叢集伺服器的負載。

動態分散式元資料管理——由於檔案系統的元資料操作基本佔了檔案系統負載一半,因此有效的元資料管理是整體檔案系統的關鍵。Ceph 利用創新的元資料管理,即“動態子樹分割槽”,使得元資料的管理具有適配性與智慧性,因為元資料叢集可將檔案系統的目錄層級的管理責任在上百個 MDSs 之間進行分配。(動態的)層級式分割槽在每個 MDS 的負載上保留了本地性的同時,利用有效的更新與合併預取來提高一般負載的效能。更加重要的是,元資料的負載是根據當前訪問模式來在元資料伺服器之間進行分配的,使得 Ceph 能夠有效利用可得的 MDS 資源,並在任何負載下取得近線性的 MDSs 伺服器的擴充套件效能。

可靠的自動化分散式物件儲存——大型系統由數以千計的裝置組成,天生就具有動態性:它們是增量構建的,並隨著部署新裝置或者清除老裝置時增長或者收縮,可以預見叢集中的裝置會頻繁失效,同時會有大容量的資料被建立、移動、刪除。所有這因素都要求資料的分佈要有效利用可得的資源,並且保持某個等級的複本。Ceph代理儲存資料的 OSDs 叢集中,資料遷移、複製、失效檢測及恢復的職責,並且在高的層級上,向客戶端以及元資料伺服器提供一個單一的邏輯物件儲存。這種方式使得 Ceph 可以有效平衡每個OSD的智慧性(CPU以及Memory),以此來取得可靠的,高可用的物件儲存,並且具備線性擴充套件的能力。我們將描述 Ceph 客戶端、元資料伺服器叢集的操作,分存式物件儲存,以及它們受架構特性的影響,我們也將描述原型系統的狀態。

3 客戶端操作

通過描述 Ceph 客戶端操作我們介紹了 Ceph 各元件的操作流程,以及他們與應用的互動過程。Ceph客戶端在每個執行使用者程式碼的主機上執行,並向用戶程式碼暴露檔案系統介面。在 Ceph 的原型中,客戶程式碼完全執行在使用者態,可以直接連線到客戶端,或者通過FUSE[25](一種使用者態檔案系統介面)掛載的檔案系統來訪問。每個客戶端維護自己的檔案資料 Cache,獨立於核心頁以及buffer caches,使得直接連線到客戶端的應用能夠訪問到。

3.1 檔案I/O 及其權能

當程序開啟一個檔案,客戶端傳送一個請求到MDS 叢集,某個 MDS 則遍歷檔案系統樹,並將檔名轉換為 inode,在這個 inode 中包含一個唯一的 inode 號,檔案所有者,模式,大小以及其他單個檔案的元資料。如果檔案存在,則訪問被允許,MDS 則返回 inode 號,檔案大小,以及用於影射檔案資料到儲存物件的分塊策略。同時,MDS 也返回客戶端的權能(如果有),用於表示客戶端可以執行的操作。權能當前包括4位,用來控制客戶端是否能夠讀、cache 讀、寫、buffer 寫。未來,權能將包括安全鍵,這樣使客戶端對於 OSDs 的讀寫是經過授權的[13,19] (當前的原型是對所有的客戶端都授權)。其他的 MDSs 對於檔案I/O只限於管理權能,以保證檔案的一致性與文件正確的語義。

Ceph 通過一系列的分塊策略將檔案影射到連續的物件。為避免使用檔案分配的元資料產生,物件名字僅是 inode 號與分塊號。物件複本然後通過 CRUSH 演算法被分配到 OSDs 中,這是一個全域性範圍的對映函式(將在 5.1 節說明)。例如,如果一個或者多個客戶端開啟檔案用於讀訪問,某個 MDS 將授權這些客戶端以讀,並且快取檔案內容的許可權。通過 inode 號、佈局、檔案大小,客戶端就能夠命名並定位所有包含檔案內容的物件,然後直接從 OSDs 叢集中讀取。任何不存在的物件或者位元組區都定義為檔案的“洞”,或者資料“0”。相似的,如果一個客戶端開啟一個檔案寫,它就被授權對檔案進行寫或者快取寫的許可權,其在檔案任何位置產生的位元組都將簡單地寫到對應的 OSD 中的對應物件。客戶端在檔案關閉時放棄所有的許可權,然後向 MDS 提供檔案的大小(即最大的寫偏移),這些檔案大小重新定義了包含資料檔案的物件(可能存在)集。

3.2 客戶端同步

POSIX 語義要求讀要反映任何之前寫入的資料,並且寫是原子性的(對於交叉併發寫能夠有一定的併發順序)。當一個檔案被多個客戶端開啟寫,或者混合讀寫,MDS 應該撤銷任何讀Cache寫快取寫的權能,強制客戶端I/O對該檔案進行同步。也就是,每個應用的讀與寫都應該在 OSD 確認之前阻塞,從而將更新序列化與同步的負擔指派給了儲存每個物件的 OSD 上。當寫跨越了物件的邊界,客戶端需要受影響的物件的互斥鎖(由相應的 OSDs 授權),並且立即提交寫操作,然後釋放鎖,以求取得需要的序列順序。物件鎖也同樣用於覆蓋大的寫操作延遲,通過獲取這個鎖,然後將資料進行非同步刷出。

不用驚訝,同步 I/O 會導致應用的效能下降,尤其是對於小的讀寫操作,這是因為延遲懲罰——至少要執行一輪到OSD的操作。(我想意思是資料從發起讀寫到完成算一個 round-trip,這樣如果太多小的讀寫操作,一個 round-trip 所產生的延遲累積起來就很可觀了。)儘管在通用負載中讀與寫共享相對較少,但是這樣的場景中效能卻是一個關鍵引數。正是因為這個原因,在應用不依賴於資料的一致性的情況下,放鬆了對一致性的要求,但要付出與標準不一致的代價。

雖然通過全域性切換,Ceph 緩解了這樣的問題,但是許多其他的分散式檔案系統卻對此不太關注 [20],這是個不太講究,因此也不讓人滿意的解決方案,因為要麼犧牲系統的效能,要麼缺失系統層面的一致性。正是因為這個原因,高效能運算社群針對 POSIX 的介面提出了許多高效能運算的擴充套件,Ceph 實現了其中的一個子集。一個顯著的一個例子就是,加入了 O_LAZY 這樣的標誌位用來緩解開啟那些允許應用顯式併發共享寫的所產生的一致性問題。對於有效能要求的應用,它們會自己處理自己的一致性問題(例如在 HPC 負載中通過向檔案的不同位置寫[27]),這樣就可以允許快取讀定,其他的情況下就要進行同步讀寫。如果需要,應用也可以通過兩個呼叫來執行顯式的同步:lazyio 會將某個範圍的位元組刷到物件儲存中,並且保證之前的操作能夠反映在後續的讀操作中。通過在客戶端之間通過同步的 I/O 這樣的模式來提供正確的讀寫與共享寫語義,以此來保證 Ceph 簡潔性,同時擴充套件了應用的介面,緩解了關注效能的分散式應用程式對於一致性的要求。

3.3 名字空間操作

客戶端與檔案系統名字空間之間的互動操作是由元資料伺服器叢集來管理的。讀操作(如 readdir,stat)以及更新操作(如 unlink,chmod)都是被 MDS 同步應用的,以此保證序列性,一致性以及正確的安全性與資料安全。為了簡單起見,沒有元資料鎖或者租期鎖分配給客戶端。特別是,對於 HPC 這樣的負載,回撥則可能會以複雜性的增加這樣的代價,換取一丁點好處。而 Ceph 對於大多數的元資料訪問場景都進行了優化。對 readdir 之後的每個檔案執行 stat 操作(如 ls -l)就是極為普通的訪問模式,會對巨型目錄的訪問效能帶來巨大的傷害。在 Ceph 中,readdir 操作只需要向 MDS 傳送一個請求就可以取得整個目錄內容,包括 inode 內容。在預設情況下,如果 readdir 之後緊跟著一個或者多個 stat 操作,其僅僅是將簡略的快取的資訊返回而已,其他情況,資訊則會被丟棄。儘管這僅僅是稍微緩解了未留意的 inode 交叉修改所帶來的相關性,我們為了效能的提升也非常願意做這樣的取捨。這樣的行為可以通過 readdirplus 的擴充套件來捕獲,這個介面返回的是目錄項的 lstat 的結果(就像某些特定的 OS 所實現的 getdir 所執行的操作)。

Ceph 通過將元資料快取保持得更久一些,就可以將一致性問題進一步緩解,這正如早期的 NFS 版本所做的,NFS 在早期快取的時間典型為30秒。然而,這種方式往往打破了對於應用來講是最關鍵相關性,例如那些使用 stat 來確定檔案是否已經更新的操作——在這樣的情況下,它們要麼行為不正確,要麼需要等待舊的Cache資料超時。我們偏向於為提供正確的行為,擴充套件那些影響了效能的介面。這個選擇可以通過有多個客戶端開啟寫的檔案執行 stat 操作來說明。為了返回正確的檔案大小以及修改時間,MDS 會取消所有的寫許可權,並臨時停止更新並向所有的寫者收集最新的大小以及 mtime(修改時間)值。將且將最大的值做為 stat 的返回。此後,相應的寫權能重新恢復使客戶端可以進一步的操作。看起來,停止所有的寫操作有點過於極端,但是為了保護序列化的正確性卻是必要的。(對於單個寫者,正確的值可以從寫客戶端獲取而不需要停頓)對於不需要相關性的應用——POSIX 介面沒有專門針對它們的需求來編寫而使其受到一定的傷害——可以使用 statlite[31] 介面來獲取檔案的資訊,該介面利用位遮蔽來指定 inode 的哪些域不需要相關性。

4 動態分散式元資料

元資料操作一般佔檔案系統負載的一半左右[22],並且處於操作的關鍵路徑上,因此 MDS 叢集對於整體效能非常關鍵。在分佈檔案系統中,元資料的管理也是一個擴充套件性挑戰:儘管容量以及集合 IO 率幾乎可以通過新增更多的儲存裝置來任意擴充套件,但是元資料操作會包含更多的交叉依賴,使得擴充套件的一致性與相關性管理變得相當困難。

在 Ceph 中,檔案與目錄的元資料是非常小的,其由整個目錄(檔名)以及inode (80位元組)組成。不像傳統的檔案系統,Ceph 不需要檔案分配元資料,物件名由 inode 號組成,資料在 OSDs 上的分佈則通過 CRUSH 演算法實現。這簡化元資料負載,使得 MDS 能夠有效地管理非常巨大的檔案集合,而不管檔案大小。我們通過兩層儲存設計還進一步減少元資料與磁碟相關的 IO,使元資料的本地化最大化,並利用 DSP[30](動態子樹分割槽)來有效地進行快取。

4.1 元資料儲存

儘量 MDS 叢集的目標在於通過記憶體快取來滿足大部份的請求,但是元資料的更新卻必須安全地提交到磁碟。集合性的,打包方式,並延遲刷出日誌操作,使得每個 MDS 能夠以一種高效分散式的方式,快速地流化其更新的元資料到 OSD 叢集中。單 MDS的日誌,每個達數百兆位元組,同時合併重複的元資料更新(對於大多數負載來講很常見),因此當舊的日誌記錄最後刷出到持久化儲存時,許多的資訊已經過期了。

儘管 MDS 的恢復在我們的原型中還沒有實現,但是日誌的設計使得在MDS 失效時,另一個節點能夠快速掃描日誌來恢復失效節點記憶體中快取中的關鍵內容(為了快速啟動),通過這樣來恢復檔案系統狀態。這樣的策略提供了兩最好的實現方案:高效地將更新流化更新到磁碟(順序地),極大地壓縮了重寫負載,使得長期儲存佈局能夠為未來的讀訪問進行優化。特別地,結點(inode)內嵌在目錄裡,使得 MDS 通過一次對 OSD 的讀就可以將整個目錄進行預取,並且在負載的多數情況下都是讀取的本地的資料。將目錄內容寫到 OSD 叢集中,使用的都是與日誌元資料以及檔案相同的分塊以及分佈策略。inode 被分配到一系列的元資料伺服器中,並在我們的原型中被認為是不變的,儘管未來它們可能在檔案刪除時需要收回。任意的某個定位表(anchor table)[28]儲存一些 inode,它有多個硬連線,並能通過 inode 號進行全域性定址——所有的 inode 所產生的代價不會比普通的單連線的,同時擁有大量稀疏空間, 繁雜 inode 表更多。

圖 2:Ceph 根據當前的負載情況動態地將目錄層次結構影射到元資料伺服器上。單個目錄只有它在成為熱點的時候才會被雜湊到不同的結點上。

4.2 動態子樹分割槽

我們的主複本快取策略,讓一個授權的MDS 負責管理所有元資料的快取的關聯性,以及串化更新。大多已存在的分散式檔案系統利用某種靜態的基於樹的分割槽來表示這種授權(通過要求管理員將資料集切割成更小的靜態“卷”),當前的一些實驗性的檔案系統已經採用雜湊函式來分佈目錄以及檔案元資料[4],但卻為了負載的分期犧牲了資料的本地性。兩種方式都有關鍵的限制:靜態子樹分割槽無法處理動態負載以及資料集,而雜湊則破壞了元資料的本地性,而本地性是高效儲存與預取元資料的關鍵。

Ceph MDS 叢集基於動態了樹分割槽策略[30],通過適配,將元資料層級在結點集之間進行分佈,如圖2所示。每個 MDS 利用指數化延遲的計數器評估目錄層次中的元資料的熱度(poularity)。每個操作都遞增受影響的 inode 的計數器,以及所有它祖先結點,直到根目錄結點。通過這樣的方式向 MDS 提供了一種帶權重的負載分佈情況。MDS 的負載值會定時比較,適當的分割槽大小會被遷移,來保證負載最終是分散的。長期儲存的組合並輔以仔細構造名字空間鎖,使得這樣的遷移只需要處理記憶體中的快取並賦予相應的許可權即可,從而最小化對關聯鎖以及客戶端權能的影響。

輸入的元資料,為安全起見被寫到新的MDS 的日誌中,而兩結點中其他的日誌記錄項則用於保證結點失效時,通過授權的轉移來解決(類似於兩階段提交)。最終的結果是,基於子樹的分割槽總是進行最小字首的複製,同時又保證了本地性。當元資料在多個 MDS 之間複製時,inode 的內容被分成三組,每個都有不同的一致性語義,這包括:安全(所有者,模式等),file(大小,修改時間)以及不可變性(inode 號,建立時間,佈局等)。不可變域不會改變,安全與檔案鎖由獨立的有限狀態機來管理,每個都有不同的狀態集,傳輸的設計符合不同的訪問模式與更新模式,同時最小化加鎖的內容。例如,所有者及模式(mode)在遍歷路徑上需要安全檢查,但是很少改變,因此需要較少的狀態,而檔案鎖反映了更廣範圍的客戶端操作模式,例如通過控制 MDS 的權能來實現客戶端的權能。

4.3 流量控制

對目錄層級在多個結點之間分割槽,能夠平衡很多負載型別,但是並非總是能夠處理熱點阻塞與快取擁擠,即如很多的客戶端同時訪問同一個目錄或者檔案。Ceph 利用對於元資料的熱度的知識,來為熱點在需要時提供一種更寬的熱點分佈,這在多資料情況下不會導致相關的負擔以及目錄的本地性的損失。內容被重度訪問的目錄(如許多開啟操作)將有選擇性地在多個結點複製以分散其負載。對於大型目錄或者正在經歷重度寫負載的情況(如建立大量檔案),則將他們的內容通過檔名的雜湊在叢集之間分佈,在分佈平衡的同時,帶來的代價就是本地性的損失。

這種適配方式,允許 Ceph 採用各種粒度的分割槽大小,使其在特定場景以及某些檔案系統部分,有效地利用各種粗細的分割槽粒度。每個 MDS 都向客戶端提供關於授權以及相關 inode 結點及其祖先結點的複本的更新資訊,這樣客戶端能瞭解與其互動的檔案系統部分元資料分割槽。未來的元資料操作將直接授權(針對更新)或者根據已給的路徑的最深字首來隨機生成複本(針對讀)。通常情況下,客戶端能夠了解到不常用元資料的位置(未複製的),這樣能夠直接與對應的 MDS 進行互動。客戶端訪問熱的元資料時被告知,元資料要麼在不同的 MDS,或者多個 MDS 上,這樣將客戶端繫結,使特定的元資料塊在特定的 MDS 上,從而使熱點與快取擁擠出現之前就消除了。

5 分散式物件儲存

從高層看,Ceph 的客戶端以及元資料伺服器將物件儲存叢集(可能包含數以千計的OSDs)看成一個單獨的邏輯儲存空間。Ceph 的可靠的自動分佈物件儲存(RADOS,Reliable Autonomic Distributed Object Store)在叢集中通過代理物件複製的管理,叢集的擴充套件,以及對 OSDs 失效檢測與恢復來獲取線性的容量與效能的擴充套件能力。

圖 3:檔案被分塊成許多物件,並且組成 PG(定位組),並利用 CRUSH,一種特定的複本定位函式,向 OSDs 中進行分發

5.1 利用 CRUSH 進行資料分發

Ceph 必須將 Petabytes 級別的資料分佈到不斷演進的,具有成千上萬個儲存裝置的叢集中,這樣裝置的儲存與頻寬才能夠被有效利用。為了防止不平衡(例如最近安裝的裝置可能總是空閒)或者負載不對稱(如熱資料總是在新裝置上),我們引入將新資料隨機分配的策略,將已經存在的資料隨機遷移到新的裝置中,並且統一地將已經移除的裝置進行上的資料進行重新分配。這種隨機的方法是可靠的,因此在不同的負載下都可以很好地執行。

Ceph 首先利用簡單雜湊函式將物件影射到定位組(PGs),此函式利用可調整的位遮蔽來控制 PG 的數量。我們選擇每個 OSD 約 100 個 PGs 來平衡 OSD 的使用,這些 OSD 維護大量相關的元資料相關的複本。然後通過 CRUSH (可擴充套件雜湊下的可控的複本)[29]將 PG 指定給 OSD。這是一種準隨機的資料分佈函式,能夠有將地將 PGs 指定給有序的 OSD 列表,利用這些 OSD 來儲存複本。這不同於傳統的方法(包括其他基於物件的檔案系統),這些方法中的資料儲存不依賴任何塊以及物件元資料列表。為了定位任何物件,CRUSH 需要的僅是 PG,以及 OSD 叢集的影射:即一個壓縮的,組成叢集的層次描述的裝置。這種方法有兩個好處:一是它是完全分佈的,因此任何部分(客戶端,OSD,MDS)都可以獨立地計算任何物件的位置。第二,這種影射不會變動頻繁,因此基於分散式的元資料交換就沒有了。通過這樣的方式,CRUSH 同時解了資料分佈問題(資料存在哪的問題)以及資料位置的問題(我把資料存在哪了的問題)。通過設計,對儲存叢集的小改變,不會對於已經存在的 PG 影射造成很大的影響,因此最小化了在裝置失效或者擴充套件情況下的資料遷移。

叢集的影射層級結構被構造成與所在叢集的物理或者邏輯結構,以及可能的失效源進行對齊。例如,一個完配 OSD 的裝置可能有 4 級層級,裝滿機架的 OSDs,以有機架上的所有背板,以及背板中所有的行。每個 OSD 都有一個權重,用來控制可被賦予的相對資料量。CRUSH 根據定位規則將 PG 影射到 OSDs,這些規則定義了一定的複本等級以及對定位的限制性條件。例如,將每個 PG 都複製到3個OSDs 上,並且都位於在同一行(為防止行之間的複製資料產生的流量),但是分佈在不同的背板中(為了最小化電源失效以及交換機失效的帶來的影響)。叢集影射同時也包括失效或者非活動裝置的列表,以及一個時期資料,當影射變化時,這個時期資料就會遞增。所有的 OSD 請求都被打上標籤,其中包括客戶端的影射時期。這樣所有部分都可以對當前資料的分佈情況取得一致。遞增影射的更新在關聯的 OSDs 之間的共享,如果客戶端的資料已經過時,那麼它就會注入 OSD 回覆。

5.2 複製

與 Lustre[4]這樣的系統比較起來,Lustre 假設某個裝置通過類似於 RAID或者故障切換的 SAN 即可構造足夠可靠的 OSDs,而 Ceph 則假設在 Petabytes 或者 Exabytes 級別的系統中,裝置失效是很平常的事情。在任何時間點,可能有多個OSDs 是不可操作的。在可擴充套件的情形下,為了保證系統的可用性以及資料的安全,RADOS 通過可變的主複本複製技術來管理自己的資料複本,同時利用多個步驟來保證對效能的影響最小化。

資料是根據 PGs 來複制的,每個 PG 都影射到一個有序 n 路 OSD中(對於 n 路複製)。客戶端將所有的寫傳送到第一個未失效的 OSD 的物件 PG 中(主),然後賦給物件以及 PG 一個版本號,然後將寫轉發到所有其他複本 OSDs 中。當所有的複本都已經應用並且更新回得到了主複本,則主複本在本地應用更新,然後將寫確認傳送到客戶端。讀則將被定向到主複本。這樣的方式使用客戶端不要關心資料在不同版本之間序列化以及同步的複雜性,這些複雜性會在其他的寫者到來或者失效恢復情況下更加嚴重。同時,這也將由複本所消耗的頻寬由客戶端移到了 OSD 叢集的內部網路,這樣我們可以期望整個資源的最大可用性。複本之間的失效被忽略了,後續的恢復(請看5.5節)將可靠地恢復資料的一致性。

圖 4:RADOS 當寫已經應用到了所有的複製物件 OSDs 中的快取中返回一個 ack 確認資訊。只有當資訊提交到了磁碟才會傳送一個最終的 commit 通知給客戶端。

5.3 資料安全

在分散式儲存系統中,有兩個原因使得資料要寫到共享的儲存上。首先,首先客戶端希望自己的變更能夠讓其他的客戶端感知,並且要迅速:即寫操作應該儘可能快地對其他客戶端可見,特別是多個寫者,或者讀者寫者混合迫使客戶端執行同步操作。其次,客戶端也想知道他們所寫的資料已經安全地進行了複製到磁碟上了,因此在裝置失效時也能夠留存下來。當通知更新時,RADOS 將同步與安全分離,使得 Ceph 實現低延遲更新與高效的應用同步,以及定義良好的資料安全語義。圖4 解釋了資訊在物件寫的時候的傳送情況。主物件將更新發送給複本,然後當這些資料到達 OSD 的記憶體快取(buffer)後傳送 確認ack) 訊息,這樣同步的 POSIX 介面就可以返回到客戶端了。終極提交可能要等到幾秒鐘之後資料完全寫到了磁碟。當更新完全進行了複製,並且可以有效地容忍單個 OSD 失效時,我們就傳送 提交(commit) 訊息給客戶端,儘管這會導致客戶端延遲的增加。在預設狀態下,客戶端也會對寫操作進行快取,直到它們將其提交以避免在 PG 中的所有 OSD 同時掉電而導致的資料丟失。當從這種失效狀態中恢復時,RADOS 在接受任何新的更新時,以固定間隔重新執行之前已經確認的更新。

5.4 失效檢測

及時失效檢測對於維護資料的安全是非常關鍵的,但是當叢集的規模擴張到資料以千計的裝置後,這樣的檢測就變得相當困難了。對某種失效,例如磁碟錯誤或者資料崩潰,OSDs 自己就可以上報。但是例如使得 OSD 不可用的問題,如網路,RADOS 使每 PG 中的每個 OSD 檢測同一個 PG 中的其他 OSD,來實現一種主動的檢測。在大多數情況下,可以利用已經存在的複製流來作為活性檢測的機制,因此沒有什麼額外的負荷。如果某個 OSD 沒有從其他對端中收到資訊,就會顯式地傳送一個 ping。RADOS 會考慮兩個維度的活性:一是 OSD 的可達到性,以及是否被 CRUSH 分配資料。某個沒有反應的 OSD 將被標記成 Down,任何主複本都將其職責(即更新序列化,複製)臨時地傳遞給同一個PG 中的其他 OSD。如果 OSD 沒有快速地恢復,則其就會被標記成不在資料定位組中,則其 PG 中的其他 OSD 則加入,並且將失效的 OSD 的內容複製過來。在失效 OSD 上已經掛起的操作只需要向新的主複本重新提交即可。有大量的網路問題都可以導致 OSD 的連線性出現時斷時續,一個小的叢集監控將收集失效報告,將把間歇性的或者系統性問題(如網路分離)集中過濾。監控器(當前只實現部分)使用選舉,主動端點監控,短期租賃以及兩階段提交來共同提交叢集影射的一致性以及可訪問性。當影射更新並反映了失效以及恢復情況,受影響的 OSDs 將會增量更新其影射,然後利用已經存在的 OSD 之間的通訊流來在叢集中間進行分發。分佈檢測使得 Ceph 不用增加過度的監控負擔就可以實現快速的檢測,同時又利用集中仲裁機制解決了資料不一致性問題的出現。最重要的是,RADOS 針對 OSD 中標誌為 Down,但是沒有標記成 Out 狀態的OSD不進行初始資料的複製(例如當一半的 OSDs 都掉電後的情況)。

5.5 恢復及叢集更新

由於 OSD 的失效,恢復以及部署新儲存裝置,OSD 叢集影射是會變化的。Ceph 對這些變化的處理方式都是一樣的。為了快速恢復,OSDs對每一個 PG 的每一個物件以及最新的更新日誌(名字以及更新版本,或者刪除的物件)都維護了一個版本號。當活動的 OSD 收到更新影射的訊息,它將遍歷所有的儲存在本地的 PG,並計算 CRUSH 影射來確定其對哪一個負責,是作為主還是做複本。如果 PG 的成員有了變化,或者 OSD 剛剛啟動,那個這個 OSD 必須與 PG 中的其他 OSD 建立連線端點。對於作為複本的 PGs,OSD 向主複本提供當前PG 的版本號。如果主複本沒有最近的 PG 狀態,為了確定正確 PG 的正確內容(最近的)則從當前的或者前一個 PG 的 OSD 中取得 PG 變更的日誌(如果必要的話,也取得完整的內容)。主複本將資料的增量更新日誌(如果必要,連同完整的內容)傳送給其他的複本裝置,這樣每一部份都將取得 PG 的內容,就算它們本地的內容是有差異的。只有在主複本確認的正確的 PG 狀態,並且將其共享給了其他的複本裝置後,針對 PG 中物件的 IO才會被放行。之後,OSDs 將獨立負責從其他對端中取回丟失的資料以及更新過時的資料。如果某個 OSD 收到一個空白或者丟失的物件的請求,則會延遲處理,並將這個對像的恢復移動到處理佇列的前部。例如,如果 osd1 崩潰了,並且被標記為 Down 狀態,osd2 成為 pgA 的主複本。這時如果 osd1 恢復了,在啟動後它會請求最新的影射資訊,監控器也將其標記為啟動狀態。當 osd2 收到了最終的更新資訊,則它會意識到自己不再是 pgA 的主複本,併發送 pgA 版本號到 osd1。此時 osd1 將從 osd2 中取回 pgA 最新的更新日誌記錄,並告訴 osd2 它的內容才是最新的,當所有物件的恢復完成後,osd1 才會處理其他的請求。

由於失效恢復完全由個個的 OSDs 來驅動,每個受失效 OSD 影響的 PG 對於替換的OSD 來講都是並行恢復。這種基於FaRM(Fast Revovery   Mechanism) 的方式,減少了恢復的時間,提高了資料的整體安全性。

5.6 使用 EBOFS 的物件儲存系統

儘管許多的分散式檔案系統都使用像 ext3 這樣的檔案系統來管理底層儲存[4,12],但是我們發現這些介面的效能對於物件儲存負載來說有點差[27]。已經存在的 Kernel 介面對於限制了我們正確理解物件安全地儲存到磁碟的能力。同步寫或者日誌機制提了供相應的安全機制,但是需要要忍受較大的延遲以及效能損失。更重要的是,POSIX 介面無法支援對於元資料更新操作的原子性(例如屬性更新),而這對於管理 RADOS 的一致性是非常重要的。因此,Ceph 利用 EBOFS,即“擴充套件的基於B樹的物件檔案系統(Extent and B-tree base Ojbect File System)”來管理本地的物件儲存。通過在使用者態實現這樣的檔案系統,並直接與底層塊裝置進行交換,可以使我們定義自己的底層物件儲存介面以及更新語義,這樣的更新將更新序列化(為了同步)與磁碟提交進行分離(為了安裝)。EBOFS 支援原子事務(例如,對多個物件的寫屬性更新),當在記憶體中的快取更新之後才會返回,同時提供非同步的提交確認。在使用者態實現,除了能夠提供更大的靈活 性以及實現更容易外,也避免了繁瑣的與LinuxVFS以及頁快取(page cache)的交換,這兩者的設計都基於不同的介面與負載型別。而大多數的 Linux 檔案系統會延遲一段時間之後才會更新,而 EBOFS 則合併磁碟的寫,並側向於在連續的更新 I/O 操作中取消掛起,因為連續更新中的 I/O 掛起是多餘的。這些都給我們提供了針對底層磁碟更長的 I/O 佇列以及提高了相應的 I/O 排程效率。

使用者態的排程器也使得最終的優先負載的調控更加容易(如針對客戶端的I/O與恢復I/O),或者說提供了一種服務保證機制。EBOFS的設計核心是可靠,靈活以及完全與 B 樹整合,這樣可以來定位物件在磁碟中的位置,管理塊的分配與索引收集(PG),塊的分配是根據資料維度(開始與長度)來執行的,而不是塊列表,這樣可以使得元資料更小,也能夠使 EBOFS 更快地定位至下一個寫位置或者在資料相關的位置找到空閒空間,從而限制長期的碎片。唯一的例外是針對每個物件的塊分配資訊,所有的元資料都儲存在記憶體中,這樣即簡化了操作也提高了效能(即使針對大卷,元資料也非常小)。最後,EBOFS 合併執行 Copy-On-Write:除了超級塊的更新,資料總是寫到一個磁碟未分配的塊位置。

6 效能與擴充套件性評估

我們將原型在不同的測評環境中進行測試,證明了Ceph 的可靠性,效能及可擴充套件性。在所有的測試中, OSDs 以及 MDs 都是使用者程序,並執行在雙核 Linux 集群系統上,系統中採用的是 SCSI 磁碟,利用 TCP 來進行通訊。總的來說,每個 OSD 或者 MDS 都執行在本主機上,而其他的數以千計的客戶端例項則可能在產生負載的時候共享一個主機。

6.1 資料效能

EBOFS 提供極佳的效能以及安全語義,同時,使用 CRUSH 以及代理複製與失效、恢復操作使得資料分佈平衡,這使得整體的 IO 系統隨著 OSD 叢集的擴充套件而增加。

6.1.1 OSD 吞吐量

我們測試了14個結點的 OSD 叢集的IO效能。圖5 顯示了每個 OSD 的在不同的寫大小與不同複本數下的吞吐量。負載則通過其他 20 個結點的 400 個客戶端來產生。效能主要受裸磁碟的 IO 效能限制(大概58MB/S),並在橫軸上顯示。複本資料產生了兩倍及三倍的磁碟 IO,當 OSD 數固定的時候,導致相應的客戶端的效能降低。圖6 顯示的是,通過與 Ceph 一樣的負載比較了 EBOFS 與通用檔案系統的效能(ext3,ReiserFS,XFS)差異。客戶端同步寫大檔案,並被分割成 16MB的物件,然後再將其讀回。儘管 EBOFS 在小的讀寫效能上由於執行緒與鎖的原因有下降(比起傳統檔案系統),當 EBOFS 以大於32KB的方式寫時,其效能跟磁碟的飽和效能接近,而讀時,則因為資料在磁碟上儲存與我們寫的方式匹配,就算當它們非常大的時候,因此其效能也顯著超過它們。效能的測試使用的是乾淨的檔案系統。正如之前的設計所揭示的,EBOFS 的檔案碎片率要遠低於 ext3 檔案系統,但是我們也沒有測試其他舊的檔案系統的表現。無論在什麼情形下,我們預期 EBOFS 的效能在檔案系統使用很久之後不會表現得比這些檔案系統差。

圖5:單 OSD 寫效能。橫軸表示的是物理磁碟的上限。複本對於 OSD 的吞吐量的影響非常小,就算 ODSs 的數量是固定的。n-路 複本縮小了整體n的因子的有效吞吐量,因此複本資料必需寫到 OSDs 中。

圖6: EBOFS 與通用檔案系統的效能比較。儘管小的寫由於我們的粗鎖的影響而導致寫效能的下降,但是當寫大小大於 32KB 時 EBOFS 可能取得裸盤的飽和效能。因為 EBOFS 在大增量寫時,將資料以大連續塊方式寫入,因此它具有明顯的讀效能提升。

圖7:在不同寫大小以及複本數下的寫延遲。多於兩個複本的情況下,在小塊寫時的代價很小,因為複本的更新是同步的。對於大的同步寫,傳輸時間是決定性因素。當以大於 128KB 寫時,客戶端佔大部份的寫延遲,因為需要取得互斥鎖,同時要將資料非同步刷出。

圖8:OSD 寫效能隨著 OSD 叢集大小增加而線性增加,直到交換機在有 24 個 OSDs 後達到飽和。CRUSH 以及雜湊效能當 PGs 的變化量小於 OSD 使用時效能會得到提升。

6.1.2 寫延遲

圖7顯示了單個寫者在不同寫大小以及複本資料下的同步寫的延遲。因為主OSD 同時傳送更新到所有的複本上,因此小的寫導致了多於兩個複本下輕微的寫延遲增加。對於更多的寫者,傳輸的代價基本佔據寫延遲時間。1MB 的寫(未顯示)在單複本下需要13ms,當達到3個複本需要2.5倍的延遲時間(33ms)。當非同步刷出資料並在有互斥鎖的情況下,Ceph 客戶端在寫大於128KB的情況下要多比這個時間多一些。另外,對於寫共享的應用,可以使用 O_LAZY。由於一致性的緩解,客戶端可以快取小的寫,然後將大的非同步提交到 OSDs 中。對應用來說,其看到的唯一的延遲就來自於客戶端要填滿正在將資料刷出到磁碟的快取空間所要求的時間。

6.1.3 資料分佈與擴充套件性

Ceph 的效能隨 OSD 的擴充套件幾乎是線性增加。CRUSH 通過一種偽隨機的方式將資料進行分佈,因此 OSD 的利用就能夠準確地通過二項式建模或者常規方式分配。無論哪一個都可以取得完美的隨機過程[29]。隨著 PG 的增加,差異就下降:對於每個 OSD 100 個 PG的情況下,標準差是 10%;對於1000 個的情況下為 3%。圖 8 顯示了當叢集擴充套件時,利用 CRUSH 情況下每個 OSD 的寫吞吐。它將通過線性的方式在OSD中的 4096 到 32768 個 PGs 裡進行資料分配。比較了測試資料,線性的分佈策略極好地將負載在叢集中平衡。但是簡單的雜湊函式無法處理裝置失效以及 OSD 變動的情況。因為資料通過 CRUSH 來進行分配,如果雜湊比較亂,那麼在 PGs 較少的情況下,其吞吐會有所下降:因為 OSD 使用的差異變化大,那麼會導致請求佇列的長度會在我們客戶端的散亂的負載下發生抖動(飄移)。因為裝置有可能變得過滿或者使用過度,從而拖累效能,CRUSH 通過解除安裝所有的分配碎片到一個特定的 OSD 上從而來修正這樣的問題。與雜湊以及線性策略不同,CRUSH 同時也最小化了資料在叢集擴充套件產生的遷移,同時又保證了負載的平衡。CRUSH 的計算複雜度為 O(log(n))(對於有 n 個 OSD 的叢集),因此只需要 10 幾個微秒就可以使叢集增長到好幾千個 OSDs。

6.2 元資料效能

Ceph 的MDS 叢集提供了增強的 POSIX 語義,並且有極佳的可擴充套件性。我們測試了在沒有資料 IO 的情況下的部分工作負載,OSDs 在這些實驗裡用來單獨做為元資料儲存使用。

6.2.1 元資料更新延遲

我們首先考慮一下與元資料更新相關的延遲(如mknod 或者 mkdir)。一個客戶端產生一系列的建立檔案或者目錄的動作,為了安全起見,MDS 必須將這些日誌在 OSDs 之間進行同步。我們考慮兩個無盤 MDS,在上面所有的元資料都儲存在一個共享的 OSDs 叢集上,其中一個有個本地盤用做主 OSD,並存儲日誌。圖9(a)顯示了與元資料更新的延遲(y),包括不同的元差異元資料複本(x)(0表示完全沒有日誌)。日誌項首先被寫到主 OSD 中然後被複制到其他的 OSD中。由於有本地磁碟,最開始的從 MDS 到本地主 OSD 裝置所用的時間是最少的,這樣使得 2 複本的更新延遲與 1 複本的無盤模式中的延遲類似。在兩種情況下,多於兩個複本時,由於複本並行更新會導致增加一些額外的延遲。

6.2.2 元資料讀延遲

元資料的讀操作(如readir,stat,open)有一些複雜。圖9(b)顯示了客戶端在有 10000 個內嵌目錄情況下,使用 readir 遍歷每個目錄,並 stat 每個檔案時所產生的累積時間(y)。主 MDS 快取減少了 readdir 的時間。後續的 stat 則不受影響,因為 inode 的內容已經內嵌在了目錄中。因此一次對 OSD 的讀就可以將整個目錄的內容取到快取(cache)中。一般來說,累積的 stat 時間會在大型目錄中佔大絕大部分。後續與 MDS 的互動可以通過 readdir 的額外操作來消除。在這個操作中,stat 操作與 readdir 操作會被繫結在一個單一的操作裡,或者通過釋放 POSIX,使得 stat 後立即跟著 readdir 來為客戶端產生 Cache(這是預設行為)。

(a) 帶有有盤或者無盤的元資料更新延遲,0 表示沒有日誌。

(b) 在檔案系統中遍歷時的累積時間。

圖9:使用本地磁碟可以降低寫延遲,因為沒有開始我網路來回開銷。當使用 readdirplus 或者緩和一致性使得 MDS 在執行 readdir 後呼叫 stat 時不需要與 MDS 進行互動,因此讀能從中 Cache 中受益。

圖10:每個 MDS 的吞吐在不同的負載下與叢集大小下的表現。當叢集增大到 128 個結點時,效能下降不會多於 50%,在大多的負載下,不會處於線性擴充套件線之下(水平線),這使得在現有系統上大幅提高效能。

6.2.3 元資料擴充套件

我們評測了元資料的擴充套件性,利用的是處於LLNL(Lawrence Livermore National Laboratory,勞倫斯利夫摩爾國家實驗室)的 430 個結點的 alc Linux 叢集的部分結點。圖10顯示了每個 MDS 作為 MDS 叢集大小的函式的吞吐量(y),這樣橫軸就完美地表現出線性規模。在 mkdir 的負載中,每個客戶端建立一個內嵌有 4 層的目錄,並在每個目錄下生成 10 個檔案。MDS 的平均吞吐量在小叢集中的 2000 ops/MDS,到128個MDS 結點的叢集中的 1000ops/MDS(總體超過 100000 ops/S)。在 makefile 的負載中,每個客戶端建立數千個檔案到一個目錄下,當高等等級的寫被檢測到時,Ceph 對共享的目錄進行雜湊,然後將目錄的修改時間在 MDS 結點之間進行同步。開啟共享的負載是通過讓每個客戶端重複開啟關閉10個共享檔案的方式來驗證。在 openssh 的負載中,每個客戶端重新執行檔案系統跟蹤,並在一個私有目錄下進行編譯。另一種方式則是使用共享 /lib 目錄來做一般共享,而其他的共享 /usr/include,這個目錄會被重度讀取。開啟共享以及openssh+include 負載具有最密集的讀操作,因此顯示了最糟糕的擴充套件行為,因為我們認為沒有客戶端複本的選擇問題。openssh+lib 擴充套件的情況要比一般可分離 makedir 情況要好一些,因為它包括相對較少的元資料修改以及共享。儘管我們認為在訊息層網路與執行緒的競爭在更大的 MDS 叢集中會進一步降低效能,但是專門用於測試在大型叢集裡的專有訪問模式時間有限,導致沒有對其進行全面的測試與調查。圖11展示了4個,16個以及64個MDS結點的叢集在make dir 負載的情況下的延遲(y)與單 MDS 吞吐(x)的情況。越大的叢集對於負載的分擔情況越不理想,導致了更低的單 MDS 吞吐量(但是,對於整體來說是越大的)以及更高的延遲。

圖11:在不同叢集大小(makedirs 產生的負載)平均延遲與單MDS吞吐量。

儘管線性擴充套件並不完美,但是一個128結點的 MDS 叢集執行我們的原型時,能夠每秒提供25萬個元資料操作(128結點,平均2000ops/S)。由於無數操作與資料的IO是無關的,並且元資料大小與檔案大小無關,視檔案大小,這就相當於安裝了數百 P 資料的儲存。例如,在 LLNL 的“藍色基因/L”建立了檢查點的科學計算應用上,包括了 64000 個點,而每個結點有兩個處理器,並且向同一個目錄中不同的檔案寫入資料(有點像 Makefile 這樣的負載)。當前的儲存系統峰值達到 6000ops/S,然後需要花數分鐘來完成檢查點,而 128 結點的 Ceph MDS 叢集在2秒中內就可以完成。如果每個檔案都是 10MB(對於 HPC 的應用中是比較小的),以及 OSD 保持50MB/S,25000 個 OSD 達到飽合的情況下(如果兩複本則為 50000),這樣的叢集寫能夠達到 1.25TB/S。250GB 的 OSDs 可以組合成 6 PB 的叢集。更為重要的是,Ceph 的動態元資料分佈使得 MDS 叢集(任何大小)是按照當前的負載來分佈元資料的,就算所有的客戶端訪問之前存於單個 MDS 之上的元資料。這樣就使得其比任何的靜態分割槽策略都更能夠應對不同的應用情況。

7 經驗

我們很高興,並驚訝於在我們的設計中,檔案的分配元資料以及分佈函式是如此簡單。雖然這對於函式本身提出了更高的要求,但是隻要我們精確地實現了相應的需求,CRUSH 就能夠提供相應的可擴充套件性,靈活性與可靠性。這不但使我們能夠向客戶端以及 OSDs 提供完整,獨立的的資料分佈的知識的同時,也極大地簡化了元資料負載,後續也可以使我們能夠代理資料複本的處理,包括遷移、失效檢測,OSDs 的恢復,並將這些機制以有效的方式在叢集中分佈,同時也平衡了系統資源如 CPU以及記憶體的使用。RADOS 也為未來的改進打開了方便之門,將 OSD 的模型進行更智慧的影射,例如位錯誤檢測(就像 Google File System[7]中所做的)以及根據負載情況的動態複本(類似於AutoRAID[34])。儘管使用已經存在的核心檔案系統做為本地物件儲存(就像其他很多的檔案系統所做的[4,7,9])有非常大的吸引力,但是我們很早就意識到為物件儲存系統定製一個不同的檔案系統,會為物件負載提供更好的效能。

我們所沒有料到的是,已有的檔案系統介面對於我們的需求來講有如此大的差異,這成為我們開發 RADOS 的複本與可靠性機制的最根本的原因。EBOFS 在使用者態下進行開發進展如此之快,同時提供了非常好的效能,也向我們的應用暴露了很好的介面。在 Ceph 中所得到的最大的教訓就是 MDS 負載均衡的重要性要先於全域性的可擴充套件性,以及元資料在存於哪,什麼時候存的選擇上的複雜性。儘管我們的設計原則與目標看起來非常簡單,但是在數百個 MDS 中的負載的分佈與演化卻有很多精巧之處。最明顯的,MDS 的效能有很多的指標,例 CPU,記憶體(以及Cache),包括網路,IO 限制,這些問題任何時候都可能成為效能約束。另外,有時在總體的吞吐量以及公平性上的平衡點很難去定量分析;在某種不平衡的元資料分佈環境下能夠提高系統的總體吞吐量[30]。客戶端介面的實現,我們預期會有更大的挑戰。儘管使用 FUSE 極大地簡化了實現,但同時也引入了特有的問題。DIRECT_IO 繞過了核心的頁綁存,但不支援 mmap,使得我們不得不修改 FUSE 來無效掉乾淨的頁來解決這個問題。就算是最簡單的應用操作,FUSE 也需要實現自己的安全檢查,導致了大量的 getattrs(stat) 操作。最後,核心與使用者態基於頁的 IO 操作,限制了總體的 IO 效能。儘管直接與客戶端連線避免了 FUSE 的問題,在系統過載時,使用者空間的呼叫會引入一些問題(大多數我們都已經全面地檢查過了),不可避免地需要我們在核心態的去實現客戶端。

8 相關工作

高效能可擴充套件的檔案系統一直以來都是HPC 社群的目標,這樣的應用會使得檔案系統要承擔很重的負載[18,27]。儘管很多的檔案系統都滿足這樣的需求,但是它們卻無法提供與 Ceph 一樣的可擴充套件性。像 OceanStore 以及 Farsite 這樣的大規模系統,都是設計用來提供高可靠性的 PB 級別的儲存,也能夠同時向數千個客戶端提供訪問獨立檔案,但是受限於其子系統的(例如名字查詢)的瓶頸限制,它們無法向成由千上萬個協同客戶端提供高效能地訪問某個小檔案集。相反地,並行的檔案系統像 Vest[6],Galley[17],PVFS[12],以及 Swift 對於資料有擴充套件性支援,就是將資料在多個磁碟之間進行條帶化,以此來取得非常高的傳輸率,但是對於可擴充套件元資料訪問以及高可靠的資料分佈缺乏良好支援。例如,Vesta 允許應用將他們的資料存在磁碟上,並允許獨立地訪問磁碟上的資料,而不需要訪問元資料。然而,與其他很多並行檔案系統一樣,Vesta 並不提供元資料查詢的擴充套件性支援。結果,這些檔案系統都無一例外地在訪問小檔案時,或者需要許多的元資料操作時,系統性能很差。他們都有檔案塊分配的問題:塊要麼集中分配,要麼通過一種鎖機制進行分配,這導致他們在面對數千個客戶端訪問數千個磁碟的寫請求的時候不能提供很好的可擴充套件性。

GPFS 以及 StorageTank 部分地將元資料與資料管理解藕了,但是由於有對於磁碟塊的使用以及元資料分佈架構的限制,這種解藕是很有限的。基於網格的檔案系統,像 LegionFS[33] 設計用於廣泛的使用領域,但對在高效能的本地系統中卻沒有進行優化。相似的,GFS(Google File System) 對於大檔案以及包含大容量寫與附加寫這類的大負載有了優化。像Sorrento[26],其目標是用於一些非 Posix 語義的應用中。最近,很多的檔案系統以及平臺,包括 Federated Array of Bricks(FAB)[23]以及 pNFS[9] 都圍繞網路附加儲存進行設計[8]。Lustre[4],Panasas 檔案系統[32], ZFS,Sorrento 以及 Kybos[35] 都是基於物件儲存的方案,並與 Ceph 非常相近。然而,他們中沒有一個像 Ceph 一樣,將可擴充套件、可適配元資料管理,可靠性以及容錯性集於一身。Lustre 以及 Panasas 在特定的失效下能夠代理 OSDs 的責任,並對有效分佈元資料管理提供了一定的支援,但卻限制了它們的可擴充套件性和效能。另外,Sorrento 使用了一致雜湊是一個例外,所有其他系統都使用顯式的檔案影射來指定物件的儲存位置,因此對於新加入裝置加入後的負載均衡提供的支援有限。這導致負載的不對稱性以及很差的資源利用率,而 Sorrento 的雜湊分佈,缺乏像 CRUSH 對於有效的資料遷移,裝置權重分配以及域失效的支援。

9 未來的工作

某些 Ceph 核心模組還沒有實現,包括 MDS 失效檢測以及幾個 Posix 呼叫。兩個安全架構以及協議變體正在考慮當中,但是還沒有完成一個[13,19]。我們也打算調查一下的客戶端在名字空中對 inode 轉換元資料的回撥機制的可行性。對於檔案系統靜態區域,這使得開啟操作(用於讀)不用與 MDS互動即可完成。因此,幾個 MDS 的增強功能也在計劃中,包括建立目標結構的任意子樹的快照功能。儘管在對某個目錄或者檔案的訪問出現擁塞時,Ceph 會動態複製元資料,但是對於資料來說卻還沒有這樣的功能。我們計劃允許 OSDs 能夠根據負載動態調整單個物件的複本級別,並且在 PG 中多個 OSDs 之間分佈 read 流量。這可以使得能夠可擴充套件地訪問少量的資料,並且可以在合適粒度的 OSD 間利用與 D-SPTF[15]相似的負載平衡機制。最後,我們還工作於開發一種服務質量框架,使得合併基於型別的流量優先機制和 OSD 有管理的頻寬與延遲保證。另外,為了支援應用的 QoS 需求,使能夠利用常規流量即可平衡 RADOS 複製與恢復操作。許多的 EBOFS 的增強功能也在計劃中,包括增強的分配邏輯,資料搜尋,校驗以及其他的位錯誤檢測機制的增強等,以此來保證資料安全。

10 結論

通過佔用設計空間中的一個唯的點?,Ceph提出了儲存系統的三個關鍵問題——可擴充套件性,效能和可靠性。通過分離設計假設,像幾乎所有檔案系統中都存在的分配列表,我們就可以最大化地將資料的元資料管理與資料進行分離,並且進行獨立地擴充套件。這樣的分離依賴於 CRUSH,一種產生準隨機的分佈函式,使得客戶端能夠計算物件的位置不是是查的他們的位置。為了保證資料的安全性,CRUSH 強制資料複本在不同的失效域中分佈,這樣又可以有效地處理大型儲存系統的天生的動態性,在這樣的系統中,裝置失效,擴充套件,重構都是很平常的。RADOS 在 OSDs 之間進行智慧地調整,以此來管理資料的複製,失效檢測與恢復,低階磁碟分配,排程與資料遷移,而不需要一個或者多箇中央的伺服器。儘管物件可以當成普通的檔案儲存在通用的檔案系統中,但是EBOFS提供了更好的語義以及更好的效能,這正是 Ceph 的負載以及介面需求所要求的。最後,Ceph的元資料管理框架解決了高可擴充套件性的儲存叢集中最煩人的問題,即如何來有效地提供單一且一致的目錄層級的同時,又遵守 Posix 語義,並且隨著元資料伺服器的增加,效能能夠隨之增強。Ceph 的動態子樹分割槽是獨特的可擴充套件方案,不僅提供了效率,也提供了針對不同負載的可適配能力。Ceph 在 LGPL 協議下進行授權,並可在 http://ceph.sourceforge.net/ 取得。

致謝

本工作是在美國能源部,並通過加洲大學,勞倫斯.利夫摩爾國家實驗室贊助下完成的,合同號為W-7405-Eng-48。研究工作部分由勞倫斯.利夫摩爾,Los Alamos,以及 Sandia 國家實驗室提供基金。我們在此感謝 Bill Loewe, Tyce McLarty,Terry Heidelbeg, 與 LLNL 中的每個人,他們與我們一起討論儲存系統的方方面面以及其中的困難,他們也幫助我們利用了兩天 alc 專用訪問時間。我們也要感謝 IBM 捐助了32結點的叢集,以此來協助大多數 OSD 效能測試,以及國家科學基金,他們支付了交換機升級的費用。Chandu Thekkath(我們的導師),包括那些隱名的評論人,還有 Theodore Wong 他們都提供了很多有價值的回饋,我們同時也感謝儲存系統研究中心(Storage Systems Research Center)的學生與工作人員,他們提供了很多幫助與支援。

參考文件

[1] A. Adya, W. J. Bolosky,M. Castro, R. Chaiken, G. Cermak, J. R. Douceur, J. Howell, J. R. Lorch, M.Theimer, and R.Wattenhofer. FARSITE: Federated, available, and reliable storagefor an incompletely trusted environment.

In Proceedings of the5th Symposium on Operating Systems Design and Implementation (OSDI), Boston,MA, Dec. 2002. USENIX.

[2] P. A. Alsberg and J. D.Day. A principle for resilient sharing of distributed resources. In Proceedingsof the 2nd International Conference on Software Engineering, pages 562–570.IEEE Computer Society Press, 1976.

[3] A. Azagury, V. Dreizin,M. Factor, E. Henis, D. Naor,  N.Rinetzky, O. Rodeh, J. Satran, A. Tavory, and L. Yerushalmi. Towards an objectstore. In Proceedings of the 20th IEEE / 11th NASA Goddard Conference on MassStorage Systems and Technologies, pages 165–176, Apr. 2003.

[4] P. J. Braam. The Lustrestorage architecture. http://www.lustre.org/documentation.html, Cluster File Systems,Inc., Aug. 2004.

[5] L.-F. Cabrera and D. D.E. Long. Swift: Using distributed disk striping to provide high I/O data rates.Computing Systems, 4(4):405–436, 1991.

[6] P. F. Corbett and D. G.Feitelson. The Vesta parallel file system. ACM Transactions on ComputerSystems, 14(3):225–264, 1996.

[7] S. Ghemawat, H.Gobioff, and S.-T. Leung. The Google file system. In Proceedings of the 19thACM Symposium on Operating Systems Principles (SOSP ’03), Bolton Landing, NY,Oct. 2003. ACM.

[8] G. A. Gibson, D. F.Nagle, K. Amiri, J. Butler, F. W. Chang, H. Gobioff, C. Hardin, E. Riedel, D.Rochberg, and J. Zelenka. A cost-effective, high-bandwidth storage architecture.In Proceedings of the 8th International

Conference onArchitectural Support for Programming Languages and Operating Systems (ASPLOS),pages 92– 103, San Jose, CA, Oct. 1998.

[9] D. Hildebrand and P.Honeyman. Exporting storage systems in a scalable manner with pNFS. TechnicalReport

CITI-05-1, CITI,University of Michigan, Feb. 2005.

[10] D. Karger, E. Lehman,T. Leighton,M. Levine, D. Lewin, and R. Panigrahy. Consistent hashing andrandom trees: Distributed caching protocols for relieving hot spots on theWorld Wide Web. In ACM Symposium on Theory of Computing, pages 654–663, May1997.

[11] J. Kubiatowicz, D.Bindel, Y. Chen, P. Eaton, D. Geels, R. Gummadi, S. Rhea, H. Weatherspoon, W.Weimer, C. Wells, and B. Zhao. OceanStore: An architecture for global-scalepersistent storage. In Proceedings of the 9th International Conference onArchitectural Support for Programming Languages and Operating Systems (ASPLOS),Cambridge, MA, Nov. 2000. ACM.

[