Ceph 獨一無二地用統一的系統提供了對象、塊、和文件存儲功能,它可靠性高、管理簡便、並且是自由軟件。 Ceph 的強大足以改變貴公司的 IT 基礎架構、和管理海量數據的能力。Ceph 可提供極大的伸縮性——供成千用戶訪問 PB 乃至 EB 級的數據。 Ceph 節點以普通硬件和智能守護進程作為支撐點, Ceph 存儲集群組織起了大量節點,它們之間靠相互通訊來復制數據、並動態地重分布數據。

CEPH 存儲集群
Ceph 提供了一個可無限伸縮的 Ceph 存儲集群,它基於 RADOS ,見論文 RADOS - A Scalable, Reliable Storage Service for Petabyte-scale Storage Clusters 。
Ceph 存儲集群包含兩種類型的守護進程:
Ceph 監視器維護着集群運行圖的主副本。一個監視器集群確保了當某個監視器失效時的高可用性。存儲集群客戶端向 Ceph 監視器索取集群運行圖的最新副本。
Ceph OSD 守護進程檢查自身狀態、以及其它 OSD 的狀態,並報告給監視器們。
存儲集群的客戶端和各個 Ceph OSD 守護進程使用 CRUSH 算法高效地計算數據位置,而不是依賴於一個中心化的查詢表。它的高級功能包括:基於 librados的原生存儲接口、和多種基於 librados 的服務接口。
數據的存儲
Ceph 存儲集群從 Ceph 客戶端接收數據——不管是來自 Ceph 塊設備、 Ceph 對象存儲、 Ceph 文件系統、還是基於 librados 的自定義實現——並存儲為對象。每個對象是文件系統中的一個文件,它們存儲在對象存儲設備上。由 Ceph OSD 守護進程處理存儲設備上的讀/寫操作。
Ceph OSD 在扁平的命名空間內把所有數據存儲為對象(也就是沒有目錄層次)。對象包含一個標識符、二進制數據、和由名字/值對組成的元數據,元數據語義完全取決於 Ceph 客戶端。例如, CephFS 用元數據存儲文件屬性,如文件所有者、創建日期、最后修改日期等等。
Note
一個對象 ID 不止在本地唯一 ,它在整個集群內都是唯一的。
伸縮性和高可用性
在傳統架構里,客戶端與一個中心化的組件通信(如網關、中間件、 API 、前端等等),它作為一個復雜子系統的唯一入口,它引入單故障點的同時,也限制了性能和伸縮性(就是說如果中心化組件掛了,整個系統就掛了)。
Ceph 消除了集中網關,允許客戶端直接和 Ceph OSD 守護進程通訊。 Ceph OSD 守護進程自動在其它 Ceph 節點上創建對象副本來確保數據安全和高可用性;為保證高可用性,監視器也實現了集群化。為消除中心節點, Ceph 使用了 CRUSH 算法。
CRUSH 簡介
Ceph 客戶端和 OSD 守護進程都用 CRUSH 算法來計算對象的位置信息,而不是依賴於一個中心化的查詢表。與以往方法相比, CRUSH 的數據管理機制更好,它很干脆地把工作分配給集群內的所有客戶端和 OSD 來處理,因此具有極大的伸縮性。 CRUSH 用智能數據復制確保彈性,更能適應超大規模存儲。下列幾段描述了 CRUSH 如何工作,更詳細的機制請參閱論文: CRUSH - 可控、可伸縮、分布式地歸置多副本數據 。
集群運行圖
Ceph 依賴於 Ceph 客戶端和 OSD ,因為它們知道集群的拓撲,這個拓撲由 5 張圖共同描述,統稱為“集群運行圖”:
- Montior Map: 包含集群的 fsid 、位置、名字、地址和端口,也包括當前版本、創建時間、最近修改時間。要查看監視器圖,用 ceph mon dump 命令。
- OSD Map: 包含集群 fsid 、創建時間、最近修改時間、存儲池列表、副本數量、歸置組數量、 OSD 列表及其狀態(如 up 、 in )。要查看OSD運行圖,用 ceph osd dump 命令。
- PG Map::** 包含歸置組版本、其時間戳、最新的 OSD 運行圖版本、占滿率、以及各歸置組詳情,像歸置組 ID 、 up set 、 acting set 、 PG 狀態(如 active+clean ),和各存儲池的數據使用情況統計。
- CRUSH Map::** 包含存儲設備列表、故障域樹狀結構(如設備、主機、機架、行、房間、等等)、和存儲數據時如何利用此樹狀結構的規則。要查看 CRUSH 規則,執行 ceph osd getcrushmap -o {filename} 命令;然后用 crushtool -d {comp-crushmap-filename} -o {decomp-crushmap-filename} 反編譯;然后就可以用 cat 或編輯器查看了。
- MDS Map: 包含當前 MDS 圖的版本、創建時間、最近修改時間,還包含了存儲元數據的存儲池、元數據服務器列表、還有哪些元數據服務器是 up 且 in 的。要查看 MDS 圖,執行 ceph mds dump 。
各運行圖維護着各自運營狀態的變更, Ceph 監視器維護着一份集群運行圖的主拷貝,包括集群成員、狀態、變更、以及 Ceph 存儲集群的整體健康狀況。
高可用監視器
Ceph 客戶端讀或寫數據前必須先連接到某個 Ceph 監視器、獲得最新的集群運行圖副本。一個 Ceph 存儲集群只需要單個監視器就能運行,但它就成了單一故障點(即如果此監視器宕機, Ceph 客戶端就不能讀寫數據了)。
為增強可靠性和容錯能力, Ceph 支持監視器集群;在一個監視器集群內,延時以及其它錯誤會導致一到多個監視器滯后於集群的當前狀態,因此, Ceph 的各監視器例程必須就集群的當前狀態達成一致。Ceph 總是使用大多數監視器(如: 1 、 2:3 、 3:5 、 4:6 等等)和
Paxos 算法就集群的當前狀態達成一致。
關於配置監視器的詳情,見監視器配置參考。
高可用性認證
為識別用戶並防止中間人攻擊, Ceph 用 cephx 認證系統來認證用戶和守護進程。
Note
cephx 協議不解決傳輸加密(如 SSL/TLS )、或者存儲加密問題。
Cephx 用共享密鑰來認證,即客戶端和監視器集群各自都有客戶端密鑰的副本。這樣的認證協議使參與雙方不用展現密鑰就能相互認證,就是說集群確信用戶擁有密鑰、而且用戶相信集群有密鑰的副本。
Ceph 一個主要伸縮功能就是避免了對象存儲的中央接口,這就要求 Ceph 客戶端能直接和 OSD 交互。 Ceph 通過 cephx 認證系統保護數據,它也認證運行 Ceph 客戶端的用戶, cephx 協議運行機制類似 Kerberos 。
用戶/參與者通過調用 Ceph 客戶端來聯系監視器,不像 Kerberos ,每個監視器都能認證用戶、發布密鑰,所以使用 cephx 時不會有單點故障或瓶頸。監視器返回一個類似 Kerberos 票據的認證數據結構,它包含一個可用於獲取 Ceph 服務的會話密鑰,會話密鑰是用戶的永久私鑰自加密過的,只有此用戶能從 Ceph 監視器請求服務。客戶端用會話密鑰向監視器請求需要的服務,然后監視器給客戶端一個憑證用以向實際持有數據的 OSD 認證。 Ceph 的監視器和 OSD 共享相同的密鑰,所以集群內任何 OSD 或元數據服務器都認可客戶端從監視器獲取的憑證,像 Kerberos 一樣 cephx 憑證也會過期,以使攻擊者不能用暗中得到的過期憑證或會話密鑰。只要用戶的私鑰過期前沒有泄露 ,這種認證形式就可防止中間線路攻擊者以別人的 ID 發送垃圾消息、或修改用戶的正常消息。
要使用 cephx ,管理員必須先設置好用戶。在下面的圖解里, client.admin 用戶從命令行調用 ceph auth get-or-create-key 來生成一個用戶及其密鑰, Ceph 的認證子系統生成了用戶名和密鑰、副本存到監視器然后把此用戶的密鑰回傳給 client.admin 用戶,也就是說客戶端和監視器共享着相同的密鑰。
Note
client.admin 用戶必須以安全方式把此用戶 ID 和密鑰交給用戶。
要和監視器認證,客戶端得把用戶名傳給監視器,然后監視器生成一個會話密鑰、並且用此用戶的密鑰加密它,然后把加密的憑證回傳給客戶端,客戶端用共享密鑰解密載荷就可獲取會話密鑰。會話密鑰在當前會話中標識了此用戶,客戶端再用此會話密鑰簽署過的用戶名請求一個憑證,監視器生成一個憑證、用用戶的密鑰加密它,然后回傳給客戶端,客戶端解密此憑證,然后用它簽署連接集群內 OSD 和元數據服務器的請求。
cephx 協議認證客戶端機器和 Ceph 服務器間正在進行的通訊,二者間認證完成后的每條消息都用憑證簽署過,監視器、 OSD 、元數據服務器都可用此共享的密鑰來校驗這些消息。
認證提供的保護位於 Ceph 客戶端和服務器間,沒有擴展到 Ceph 客戶端之外。如果用戶從遠程主機訪問 Ceph 客戶端, Ceph 認證就不管用了,它不會影響到用戶主機和客戶端主機間的通訊。
關於配置細節,請參考 Cephx 配置指南;關於用戶管理細節,請參考用戶管理。
智能程序支撐超大規模
在很多集群架構中,集群成員的主要目的就是讓集中式接口知道它能訪問哪些節點,然后此中央接口通過一個兩級調度為客戶端提供服務,在 PB 到 EB 級系統中這個調度系統必將成為最大的瓶頸。
Ceph 消除了此瓶頸:其 OSD 守護進程和客戶端都能感知集群,比如 Ceph 客戶端、各 OSD 守護進程都知道集群內其他的 OSD 守護進程,這樣 OSD 就能直接和其它 OSD 守護進程和監視器通訊。另外, Ceph 客戶端也能直接和 OSD 守護進程交互。
Ceph 客戶端、監視器和 OSD 守護進程可以相互直接交互,這意味着 OSD 可以利用本地節點的 CPU 和內存執行那些有可能拖垮中央服務器的任務。這種設計均衡了計算資源,帶來幾個好處:
-
OSD 直接服務於客戶端: 由於任何網絡設備都有最大並發連接上限,規模巨大時中央化的系統其物理局限性就暴露了。 Ceph 允許客戶端直接和 OSD 節點聯系,這在消除單故障點的同時,提升了性能和系統總容量。 Ceph 客戶端可按需維護和某 OSD 的會話,而不是一中央服務器。
-
OSD 成員和狀態: Ceph OSD 加入集群后會持續報告自己的狀態。在底層, OSD 狀態為 up 或 down ,反映它是否在運行、能否提供服務。如果一 OSD 狀態為 down 且 in ,表明 OSD 守護進程可能故障了;如果一 OSD 守護進程沒在運行(比如崩潰了),它就不能親自向監視器報告自己是 down 的。 Ceph 監視器能周期性地 ping OSD 守護進程,以確保它們在運行,然而它也授權 OSD 進程去確認鄰居 OSD 是否 down 了,並更新集群運行圖、報告給監視器。這種機制意味着監視器還是輕量級進程。詳情見監控 OSD 和心跳。
-
數據清洗: 作為維護數據一致性和清潔度的一部分, OSD 能清洗歸置組內的對象。就是說, Ceph OSD 能比較對象元數據與存儲在其他 OSD 上的副本元數據,以捕捉 OSD 缺陷或文件系統錯誤(每天)。 OSD 也能做深度清洗(每周),即按位比較對象中的數據,以找出輕度清洗時未發現的硬盤壞扇區。關於清洗詳細配置見`數據清洗`_。
-
復制: 和 Ceph 客戶端一樣, OSD 也用 CRUSH 算法,但用於計算副本存到哪里(也用於重均衡)。一個典型的寫情形是,一客戶端用 CRUSH 算法算出對象應存到哪里,並把對象映射到存儲池和歸置組,然后查找 CRUSH 圖來確定此歸置組的主 OSD 。
客戶端把對象寫入目標歸置組的主 OSD ,然后這個主 OSD 再用它的 CRUSH 圖副本找出用於放對象副本的第二、第三個 OSD ,並把數據復制到適當的歸置組所對應的第二、第三 OSD (要多少副本就有多少 OSD ),最終,確認數據成功存儲后反饋給客戶端。
有了做副本的能力, OSD 守護進程就可以減輕客戶端的復制壓力,同時保證了數據的高可靠性和安全性。
動態集群管理
在伸縮性和高可用性一節,我們解釋了 Ceph 如何用 CRUSH 、集群感知性和智能 OSD 守護進程來擴展和維護高可靠性。 Ceph 的關鍵設計是自治,自修復、智能的 OSD 守護進程。讓我們深入了解下 CRUSH 如何運作,如何動態實現現代雲存儲基礎設施的數據放置、重均衡、錯誤恢復。
關於存儲池
Ceph 存儲系統支持“池”概念,它是存儲對象的邏輯分區。
Ceph 客戶端從監視器獲取一張集群運行圖,並把對象寫入存儲池。存儲池的 size 或副本數、 CRUSH 規則集和歸置組數量決定着 Ceph 如何放置數據。
存儲池至少可設置以下參數:
- 對象的所有權/訪問權限;
- 歸置組數量;以及,
- 使用的 CRUSH 規則集。
詳情見調整存儲池。
PG 映射到 OSD
每個存儲池都有很多歸置組, CRUSH 動態的把它們映射到 OSD 。 Ceph 客戶端要存對象時, CRUSH 將把各對象映射到某個歸置組。
把對象映射到歸置組在 OSD 和客戶端間創建了一個間接層。由於 Ceph 集群必須能增大或縮小、並動態地重均衡。如果讓客戶端“知道”哪個 OSD 有哪個對象,就會導致客戶端和 OSD 緊耦合;相反, CRUSH 算法把對象映射到歸置組、然后再把各歸置組映射到一或多個 OSD ,這一間接層可以讓 Ceph 在 OSD 守護進程和底層設備上線時動態地重均衡。下列圖表描述了 CRUSH 如何將對象映射到歸置組、再把歸置組映射到 OSD 。
有了集群運行圖副本和 CRUSH 算法,客戶端就能精確地計算出到哪個 OSD 讀、寫某特定對象。
計算 PG ID
Ceph 客戶端綁定到某監視器時,會索取最新的集群運行圖副本,有了此圖,客戶端就能知道集群內的所有監視器、 OSD 、和元數據服務器。然而它對對象的位置一無所知。
對象位置是計算出來的。
客戶端只需輸入對象 ID 和存儲池,此事簡單: Ceph 把數據存在某存儲池(如 liverpool )中。當客戶端想要存命名對象(如 john 、 paul 、 george 、 ringo 等等)時,它用對象名,一個哈希值、 存儲池中的歸置組數、存儲池名計算歸置組。 Ceph 按下列步驟計算 PG ID 。
- 客戶端輸入存儲池 ID 和對象 ID (如 pool=”liverpool” 和 object-id=”john” );
- CRUSH 拿到對象 ID 並哈希它;
- CRUSH 用 PG 數(如 58 )對哈希值取模,這就是歸置組 ID ;
- CRUSH 根據存儲池名取得存儲池 ID (如liverpool = 4 );
- CRUSH 把存儲池 ID 加到PG ID(如 4.58 )之前。
計算對象位置遠快於查詢定位, CRUSH 算法允許客戶端計算對象應該存到哪里,並允許客戶端連接主 OSD 來存儲或檢索對象。
互聯和子集
在前面的章節中,我們注意到 OSD 守護進程相互檢查心跳並回饋給監視器;它們的另一行為叫“互聯( peering )”,這是一種把一歸置組內所有對象(及其元數據)所在的 OSD 帶到一致狀態的過程。事實上, OSD 守護進程會向監視器報告互聯失敗,互聯問題一般會自行恢復,然而如果問題一直持續,你也許得參照互聯失敗排障解決。
Note
狀態達成一致並不意味着 PG 持有最新內容。
Ceph 存儲集群被設計為至少存儲兩份對象數據(即 size = 2 ),這是保證數據安全的最小要求。為保證高可用性, Ceph 存儲集群應該保存兩份以上的對象副本(如 size = 3 且 min size = 2 ),這樣才能在``degraded`` 狀態繼續運行,同時維持數據安全。
回想前面智能程序支撐超大規模中的圖表,我們沒明確地提 OSD 守護進程的名字(如 osd.0 、 osd.1 等等),而是稱之為主、次、以此類推。按慣例,主 OSD 是 acting set 中的第一個 OSD ,而且它負責協調以它為主 OSD 的各歸置組 的互聯,也只有它會接受客戶端到某歸置組內對象的寫入請求。
當一系列 OSD 負責一歸置組時,這一系列的 OSD 就成為一個 acting set 。一個 acting set 對應當前負責此歸置組的一組 OSD ,或者說截止到某個版本為止負責某個特定歸置組的那些 OSD。
OSD 守護進程作為 acting set 的一部分,不一定總在 up 狀態。當一 OSD 在 acting set 中是 up 狀態時,它就是 up set 的一部分。 up set 是個重要特征,因為某 OSD 失敗時 Ceph 會把 PG 映射到其他 OSD 。
Note
在某 PG 的 acting set 中包含了 osd.25 、 osd.32 和 osd.61 ,第一個 osd.25 是主 OSD ,如果它失敗了,第二個 osd.32 就成為主 OSD , osd.25 會被移出 up set 。
重均衡
你向 Ceph 存儲集群新增一 OSD 守護進程時,集群運行圖就要用新增的 OSD 更新。回想計算 PG ID ,這個動作會更改集群運行圖,因此也改變了對象位置,因為計算時的輸入條件變了。下面的圖描述了重均衡過程(此圖很粗略,因為在大型集群里變動幅度小的多),是其中的一些而不是所有 PG 都從已有 OSD ( OSD 1 和 2 )遷移到新 OSD ( OSD 3 )。即使在重均衡中, CRUSH 都是穩定的,很多歸置組仍維持最初的配置,且各 OSD 都騰出了些空間,所以重均衡完成后新 OSD 上不會出現負載突增。
數據一致性
作為維護數據一致和清潔的一部分, OSD 也能清洗歸置組內的對象,也就是說, OSD 會比較歸置組內位於不同 OSD 的各對象副本的元數據。清洗(通常每天執行)是為捕獲 OSD 缺陷和文件系統錯誤, OSD 也能執行深度清洗:按位比較對象內的數據;深度清洗(通常每周執行)是為捕捉那些在輕度清洗過程中未能發現的磁盤上的壞扇區。
關於數據清洗的配置見`數據清洗`_。
糾刪編碼
糾刪碼存儲池把各對象存儲為 K+M 個數據塊,其中有 K 個數據塊和 M 個編碼塊。此存儲池的尺寸為 K+M ,這樣各塊被存儲到位於 acting set 中的 OSD ,塊的位置也作為對象屬性保存下來了。
比如一糾刪碼存儲池創建時分配了五個 OSD ( K+M = 5 )並容忍其中兩個丟失( M = 2 )。
讀出和寫入編碼塊
當包含 ABCDEFGHI 的對象 NYAN 被寫入存儲池時,糾刪編碼函數把內容分割為三個數據塊,只是簡單地切割為三份:第一份包含 ABC 、第二份是 DEF 、最后是 GHI ,若內容長度不是 K 的倍數則需填充;此函數還會創建兩個編碼塊:第四個是 YXY 、第五個是 GQC ,各塊分別存入 acting set 中的 OSD 內。這些塊存儲到相同名字( NYAN )的對象、但是位於不同的 OSD 上;分塊順序也必須保留,被存儲為對象的一個屬性( shard_t )追加到名字后面。包含 ABC 的塊 1 存儲在 OSD5 上、包含 YXY 的塊 4 存儲在 OSD3 上。
從糾刪碼存儲池中讀取 NYAN 對象時,解碼函數會讀取三個塊:包含 ABC 的塊 1 ,包含 GHI 的塊 3 和包含 YXY 的塊 4 ,然后重建對象的原始內容 ABCDEFGHI 。解碼函數被告知塊 2 和 5 丟失了(被稱為“擦除”),塊 5 不可讀是因為 OSD4 出局了。只要有三塊讀出就可以成功調用解碼函數。 OSD2 是最慢的,其數據未被采納。
被中斷的完全寫
在糾刪碼存儲池中, up set 中的主 OSD 接受所有寫操作,它負責把載荷編碼為 K+M 個塊並發送給其它 OSD 。它也負責維護歸置組日志的一份權威版本。
在下圖中,已創建了一個參數為 K = 2 + M = 1 的糾刪編碼歸置組,存儲在三個 OSD 上,兩個存儲 K 、一個存 M 。此歸置組的 acting set 由 OSD 1 、OSD 2 、 OSD 3 組成。一個對象已被編碼並存進了各 OSD :塊 D1v1 (即數據塊號為 1 ,版本為 1 )在 OSD 1 上、 D2v1 在 OSD 2 上、 C1v1 (即編碼塊號為 1 ,版本為 1 )在 OSD 3 上。各 OSD 上的歸置組日志都相同(即 1,1 ,表明 epoch 為 1 ,版本為 1 )。
OSD 1 是主的,它從客戶端收到了 WRITE FULL 請求,這意味着凈載荷將會完全取代此對象,而非部分覆蓋。此對象的版本 2 ( v2 )將被創建以取代版本 1 ( v1 )。 OSD 1 把凈載荷編碼為三塊: D1v2 (即數據塊號 1 、版本 2 )將存入 OSD 1 、 D2v2 在 OSD 2 上、 C1v2 (即編碼塊號 1 版本 2 )在 OSD 3 上,各塊分別被發往目標 OSD ,包括主 OSD ,它除了存儲塊還負責處理寫操作和維護歸置組日志的權威版本。當某個 OSD 收到寫入塊的指令消息后,它也會新建一條歸置組日志來反映變更,比如在 OSD 3 存儲 C1v2 時它會把 1,2 (即 epoch 為 1 、版本為 2 )寫入它自己的日志。因為 OSD 間是異步工作的,當某些塊還落盤(像 D2v2 ),其它的可能已經被確認存在磁盤上了(像 C1v1 和 D1v1 )。
如果一切順利,各塊被證實已在 acting set 中的 OSD 上了,日志的 last_complete 指針就會從 1,1 改為指向 1,2 。
最后,用於存儲對象前一版本的文件就可以刪除了: OSD 1 上的 D1v1 、 OSD 2 上的 D2v1 和 OSD 3 上的 C1v1 。
但是意外發生了,如果 OSD 1 掛了、同時 D2v2 仍寫完成,此對象的版本 2 一部分已被寫入了: OSD 3 有一塊但是不足以恢復;它丟失了兩塊: D1v2 和 D2v2 ,並且糾刪編碼參數 K = 2 、 M = 1 要求至少有兩塊可用才能重建出第三塊。 OSD 4 成為新的主 OSD ,它發現 last_complete 日志條目(即在此條目之前的所有對象在之前 acting set 中的 OSD 上都可用)是 1,1 那么它將是新權威日志的頭條。
在 OSD 3 上發現的日志條目 1,2 與 OSD 4 上新的權威日志有分歧:它將被忽略、且包含 C1v2 塊的文件也被刪除。 D1v1 塊將在清洗期間通過糾刪碼庫的 decode 解碼功能重建,並存儲到新的主 OSD 4 上。
詳情見糾刪碼筆記。
緩存分級
對於后端存儲層上的部分熱點數據,緩存層能向 Ceph 客戶端提供更好的 IO 性能。緩存分層包含由相對高速、昂貴的存儲設備(如固態硬盤)創建的存儲池,並配置為 緩存層;以及一個后端存儲池,可以用糾刪碼編碼的或者相對低速、便宜的設備,作為經濟存儲層。 Ceph 對象管理器會決定往哪里放置對象,分層代理決定何時把緩存層的對象刷回后端存儲層。所以緩存層和后端存儲層對 Ceph 客戶端來說是完全透明的。
詳情見緩存分級。
擴展 CEPH
你可以通過創建 ‘Ceph Classes’ 共享對象類來擴展 Ceph 功能, Ceph 會動態地載入位於 osd class dir 目錄下的 .so 類文件(即默認的 $libdir/rados-classes )。如果你實現了一個類,就可以創建新的對象方法去調用 Ceph 對象存儲內的原生方法、或者公用庫或自建庫里的其它類方法。
寫入時, Ceph 類能調用原生或類方法,對入棧數據執行任意操作、生成最終寫事務,並由 Ceph 原子地應用。
讀出時, Ceph 類能調用原生或類方法,對出棧數據執行任意操作、把數據返回給客戶端。
Ceph 類實例
一個為內容管理系統寫的類可能要實現如下功能,它要展示特定尺寸和長寬比的位圖,所以入棧圖片要裁剪為特定長寬比、縮放它、並嵌入個不可見的版權或水印用於保護知識產權;然后把生成的位圖保存為對象。
典型的實現見 src/objclass/objclass.h 、 src/fooclass.cc 、和 src/barclass 。
CEPH 協議
Ceph 客戶端用原生協議和存儲集群交互, Ceph 把此功能封裝進了 librados 庫,這樣你就能創建自己的定制客戶端了,下圖描述了基本架構。
原生協議和 LIBRADOS
現代程序都需要可異步通訊的簡單對象存儲接口。 Ceph 存儲集群提供了一個有異步通訊能力的簡單對象存儲接口,此接口提供了直接、並行訪問集群對象的功能。
- 存儲池操作;
- 快照和寫時復制克隆;
- 讀/寫對象; - 創建或刪除; - 整個對象或某個字節范圍; - 追加或裁截;
- 創建/設置/獲取/刪除擴展屬性;
- 創建/設置/獲取/刪除鍵/值對;
- 混合操作和雙重確認;
- 對象類。
對象監視/通知
客戶端可以注冊對某個對象的持續興趣,並使到主 OSD 的會話保持打開。客戶端可以發送一通知消息和載荷給所有監視者、並可收集監視者的回饋通知。這個功能使得客戶端可把任意對象用作同步/通訊通道。
數據條帶化
存儲設備都有吞吐量限制,它會影響性能和伸縮性,所以存儲系統一般都支持條帶化(把連續的信息分片存儲於多個設備)以增加吞吐量和性能。數據條帶化最常見於 RAID 中, RAID 中最接近 Ceph 條帶化方式的是 RAID 0 、或者條帶卷, Ceph 的條帶化提供了像 RAID 0 一樣的吞吐量、像 N 路 RAID 鏡像一樣的可靠性、和更快的恢復。
Ceph 提供了三種類型的客戶端:塊設備、文件系統和對象存儲。 Ceph 客戶端把展現給用戶的數據格式(一塊設備映像、 REST 風格對象、 CephFS 文件系統目錄)轉換為可存儲於 Ceph 存儲集群的對象。
Tip
在 Ceph 存儲集群內存儲的那些對象是沒條帶化的。 Ceph 對象存儲、 Ceph 塊設備、和 Ceph 文件系統把他們的數據條帶化到 Ceph 存儲集群內的多個對象,客戶端通過 librados 直接寫入 Ceph 存儲集群前必須先自己條帶化(和並行 I/O )才能享受這些優勢。
最簡單的 Ceph 條帶化形式就是一個對象的條帶。 Ceph 客戶端把條帶單元寫入 Ceph 存儲的對象,直到對象容量達到上限,才會再創建另一個對象存儲未完的數據。這種最簡單的條帶化對小的塊設備映像、 S3 、 Swift 對象或 CephFS 文件來說也許足夠了;然而這種簡單的形式不能最大化 Ceph 在歸置組間分布數據的能力,也就不能最大化性能。下圖描述了條帶化的最簡形式:
如果要處理大尺寸圖像、大 S3 或 Swift 對象(如視頻)、或大的 CephFS 目錄,你就能看到條帶化到一個對象集中的多個對象能帶來顯著的讀/寫性能提升。當客戶端把條帶單元並行地寫入相應對象時,就會有明顯的寫性能,因為對象映射到了不同的歸置組、並進一步映射到不同 OSD ,可以並行地以最大速度寫入。到單一磁盤的寫入受限於磁頭移動(如:6ms 尋道時間)和存儲設備帶寬(如:100MB/s), Ceph把寫入分布到多個對象(它們映射到了不同歸置組和 OSD ),這樣可減少每設備尋道次數、聯合多個驅動器的吞吐量,以達到更高的寫(或讀)速度。
Note
條帶化獨立於對象復制。因為 CRUSH 會在 OSD 間復制對象,數據條帶是自動被復制的。
在下圖中,客戶端數據條帶化到一個對象集(下圖中的 object set 1 ),它包含 4 個對象,其中,第一個條帶單元是 object 0 的 stripe unit 0 、第四個條帶是 object 3 的 stripe unit 3 ,寫完第四個條帶,客戶端要確認對象集是否滿了。如果對象集沒滿,客戶端再從第一個對象起寫入條帶(下圖中的 object 0 );如果對象集滿了,客戶端就得創建新對象集(下圖的 object set 2 ),然后從新對象集中的第一個對象(下圖中的 object 4 )起開始寫入第一個條帶( stripe unit 16 )。
三個重要變量決定着 Ceph 如何條帶化數據:
- 對象尺寸: Ceph 存儲集群里的對象有最大可配置尺寸(如 2MB 、 4MB 等等),對象尺寸必須足夠大以便容納很多條帶單元、而且應該是條帶單元的整數倍。
- 條帶寬度: 條帶都有可配置的單元尺寸(如 64KB )。 Ceph 客戶端把數據等分成適合寫入對象的條帶單元,除了最后一個。條帶寬度應該是對象尺寸的分片,這樣對象才能 包含很多條帶單元。
- 條帶數量: Ceph 客戶端把一系列條帶單元寫入由條帶數量所確定的一系列對象,這一系列的對象稱為一個對象集。客戶端寫到對象集內的最后一個對象時,再返回到第一個。
Important
把集群投入生產環境前要先測試條帶化配置的性能,因為把數據條帶化到對象中之后這些參數就不可更改了。
Ceph 客戶端把數據等分為條帶單元並映射到對象后,用 CRUSH 算法把對象映射到歸置組、歸置組映射到 OSD ,然后才能以文件形式存儲到硬盤上。
Note
因為客戶端寫入單個存儲池,條帶化到對象的所有數據也被映射到同一存儲池內的歸置組,所以它們要使用相同的 CRUSH 圖和相同的訪問權限。
CEPH 客戶端
Ceph 客戶端包括數種服務接口,有:
- 塊設備: Ceph 塊設備(也叫 RBD )服務提供了大小可調、精煉、支持快照和克隆的塊設備。為提供高性能, Ceph 把塊設備條帶化到整個集群。 Ceph 同時支持內核對象( KO ) 和 QEMU 管理程序直接使用``librbd`` ——避免了內核對象在虛擬系統上的開銷。
- 對象存儲: Ceph 對象存儲(也叫 RGW )服務提供了 `RESTful 風格`_的 API ,它與 Amazon S3 和 OpenStack Swift 兼容。
- 文件系統: Ceph 文件系統( CephFS )服務提供了兼容 POSIX 的文件系統,可以直接 mount 或掛載為用戶空間文件系統( FUSE )。
Ceph 能額外運行多個 OSD 、 MDS 、和監視器來保證伸縮性和高可靠性,下圖描述了高級架構。
CEPH 對象存儲
Ceph 對象存儲守護進程, radosgw ,是一個 FastCGI 服務,它提供了 `RESTful 風格`_ HTTP API 用於存儲對象和元數據。它位於 Ceph 存儲集群之上,有自己的數據格式,並維護着自己的用戶數據庫、認證、和訪問控制。 RADOS 網關使用統一的命名空間,也就是說,你可以用 OpenStack Swift 兼容的 API 或者 Amazon S3 兼容的 API ;例如,你可以用一個程序通過 S3 兼容 API 寫入數據、然后用另一個程序通過 Swift 兼容 API 讀出。
S3/Swift 對象和存儲集群對象比較
Ceph 對象存儲用對象這個術語來描述它存儲的數據。 S3 和 Swift 對象不同於 Ceph 寫入存儲集群的對象, Ceph 對象存儲系統內的對象可以映射到 Ceph 存儲集群內的對象; S3 和 Swift 對象卻不一定 1:1 地映射到存儲集群內的對象,它有可能映射到了多個 Ceph 對象。
詳情見 Ceph 對象存儲。
CEPH 塊設備
Ceph 塊設備把一個設備映像條帶化到集群內的多個對象,其中各對象映射到一個歸置組並分布出去,這些歸置組會分散到整個集群的 ceph-osd 守護進程上。
Important
條帶化會使 RBD 塊設備比單台服務器運行的更好!
精簡的、可快照的 Ceph 塊設備對虛擬化和雲計算很有吸引力。在虛擬機場景中,人們一般會用 Qemu/KVM 中的 rbd 網絡存儲驅動部署 Ceph 塊設備,其中宿主機用 librbd 向客戶機提供塊設備服務;很多雲計算堆棧用 libvirt 和管理程序集成。你可以用精簡的 Ceph 塊設備搭配 Qemu 和``libvirt`` 來支持 OpenStack 和 CloudStack ,一起構成完整的方案。
現在``librbd``還不支持其它管理程序,你也可以用 Ceph 塊設備內核對象向客戶端提供塊設備。其它虛擬化技術,像 Xen 能訪問 Ceph 塊設備內核對象,用命令行工具 rbd 實現。
CEPH 文件系統
Ceph 文件系統( Ceph FS )提供與 POSIX 兼容的文件系統服務,坐於基於對象的 Ceph 存儲集群之上,其內的文件被映射到 Ceph 存儲集群內的對象。客戶端可以把此文件系統掛載在內核對象或用戶空間文件系統( FUSE )上。
Ceph 文件系統服務包含隨 Ceph 存儲集群部署的元數據服務器( MDS )。 MDS 的作用是把所有文件系統元數據(目錄、文件所有者、訪問模式等等)永久存儲在相當可靠的元數據服務器中內存中。 MDS (名為 ceph-mds 的守護進程)存在的原因是,簡單的文件系統操作像列出目錄( ls )、或進入目錄( cd )這些操作會不必要的擾動``OSD``。所以把元數據從數據里分出來意味着 Ceph 文件系統能提供高性能服務,又能減輕存儲集群負載。
Ceph FS 從數據中分離出了元數據、並存儲於 MDS ,文件數據存儲於存儲集群中的一或多個對象。 Ceph 力爭兼容 POSIX 。 ceph-mds 可以只運行一個,也可以分布於多台物理機器,以獲得高可用性或伸縮性。
- 高可用性: 多余的 ceph-mds 例程可處於 standby (待命)狀態,隨時准備替下之前處於 active (活躍)狀態的故障 ceph-mds 。這可以輕易做到,因為所有數據、包括日志都存儲在 RADOS 上,這個轉換過程由 ceph-mon 自動觸發。
- 伸縮性: 多個 ceph-mds 例程可以同時處於 active 狀態,它們會把目錄樹拆分為子樹(和單個熱點目錄的分片),在所有活躍服務器間高效地均衡負載。
Important
譯者:雖然文檔這么說,但實踐中還不推薦這樣做, MDS 穩定性尚不理想。多個活躍的 MDS 遠沒一個穩定,即便如此,您也應該先配置起幾個 MDS 備用。
待命( standby )和活躍( active ) MDS 可組合,例如,運行 3 個處於 active 狀態的 ceph-mds 例程以實現擴展、和 1 個 standby 例程以實現高可用性。