本文翻譯自:http://docs.ceph.com/docs/hammer/architecture/
一些名詞的翻譯方式:
scalable :可擴展性
high availability:高可用
map:圖
cluster map:集羣運行圖
monitor:監視器
acting set:運行集
up set:在線集
hyperscale:超大規模
data scrub:數據清洗
peering:互聯
rebalance:重平衡
full write:一次完整地寫
tiering:層
cache tiering:緩存層
ceph體系結構圖:
ceph集羣
根據ceph的相關論文,ceph基於RADOS來提供無限擴展的能力,一個ceph存儲集羣包含兩種類型的守護進程:
監視器(Monitor)
OSD守護進程(
OSD Daemon,如下稱osd)
ceph集羣從ceph客戶端接收數據(客戶端能夠是一個ceph的塊設備,ceph的對象存儲網關,ceph的文件系統或者是基於librados寫的程序),並以對象的形式存儲起來。每一個對象就像文件系統中的一個文件,osd負責在存儲設備上的讀寫操做。
osd在一個扁平的命名空間內以對象的形式保存數據。每一個對象都包含標識符(identifier),二進制數據(binary data)和以name/value對組成的元數據(metadata)。元數據的語義徹底由ceph客戶端來決定,好比,CephFS就用元數據來存儲文件的各類屬性。
注意:對象id在整個集羣中是惟一的
在傳統架構中客戶端須要與一箇中心組件進行通訊,這使得系統存在單點問題,而且可能成爲性能和可擴展性的瓶頸。Ceph則沒有這種中心式的網關,客戶端直接與osd進行通訊。osd會將對象複製到其餘節點上來保證數據的安全和實現高可用,同時,ceph還有一套監控集羣來實現高可用。ceph是經過一種叫crush的算法來實現去中心化的。
ceph客戶端和osd都使用crush算法來計算對象存儲的位置,而不是經過一箇中心式的表來查詢。crush提供的這種數據管理機制更好,更方便大規模地擴展集羣,由於定位對象的工做都交給各個客戶端和osd了。crush使用智能數據複製的方式來確保彈性,更加適合超大規模集羣。下面幾節咱們詳細介紹一下crush算法的一些細節:
ceph客戶端和osd都知道集羣的拓撲結構,該結構由下面5張圖組成,統稱爲「集羣運行圖」。
- monitor map:包含了集羣的fsid,位置,地址名稱和端口,也包含了當前的版本,建立時間,最後修改時間。要查看監視器圖,可使用命令:ceph osd dump
- osd map:包含了集羣的fsid,建立和最後修改時間,pool列表,副本數量,pg數量,osd列表和他們的狀態(up,in)。要查看osd圖,能夠用命令:ceph osd dump
- pg map:包含pg版本,時間戳,最後一次osd圖的版本,full radio,每一個pg上的詳情如pg id,up set,acting set,pg狀態(active + clean),每一個pool的數據使用統計信息。
- crush map:包含了存儲設備列表,失敗域層級結構(device,host,rack,row,room等),存儲數據時遍歷這些層級的規則。要查看crush圖,可使用命令:ceph osd getcrushmap -o {filename},而後使用命令反編譯一下:crushtool -d {comp-crushmap-filename} -o {decomp-rushmap-filename},而後可使用cat命令查看反編譯後的圖。
- mds map:包含當前的mds運行圖版本,建立時間,最後修改時間,同時也包含了保存元數據的pool,元數據服務器列表,哪些元數據服務器是up狀態和哪些是in狀態。要查看mds圖,可使用命令:ceph mds dump
高可用監視器
ceph客戶端讀寫數據前必須從監視器獲取一份最新的集羣運行圖。集羣能夠只有一臺監視器,只不過這樣會存在單點問題。
爲了使集羣高可用,ceph支持使用一套監視器集羣,使用Paxos協議來使監視器之間對於當前集羣狀態達成一致。
高可用認證
爲了認證用戶身份和防止中間人攻擊,ceph經過cephx認證系統來認證用戶和守護進程。
注意:cephx協議並不對數據進行加解密。
cephx使用共享密鑰進行認證,因此客戶端和監視器集羣都有一份密鑰。
要使用cephx,管理員須要先設置用戶(users)。能夠經過client.admin用戶執行命令:cephauth get-or-create-key來生成用戶名和密鑰,這時監視器會保有一份密鑰,以下圖所示:
客戶端向監視器發起認證請求,監視器返回一份受權過的數據,有點像Kerberos裏的ticket,包含一個會話key。key使用用戶的密鑰加過密,因此只有該用戶才能解密這個key來訪問監視器。接着客戶端使用會話key請求監視器,監視器這時會返回一個加密過的ticket,以下圖所示:
客戶端解密這個ticket,對發送到osd和元數據服務器的數據進行簽名。osd,元數據服務器和監視器共享一份密鑰,因此均可以校驗客戶端的請求。就像Kerberos,cephx ticket有過時時間。
使用這種方式,只要用戶的session key沒有泄露就不會被攻擊者僞造或修改消息。不過,這種認證只保護ceph客戶端到服務器這段路程,若是用戶從遠程訪問客戶端,則從用戶到客戶端這段路程是不受保護的。
智能進程使超大規模成爲可能
ceph沒有中心節點,osd和客戶端都知道集羣的全部信息,每一個osd都知道集羣中全部其餘osd的存在,這樣osd就能夠直接與其餘osd和監視器通訊。另外,客戶端也能夠直接與osd通訊。
這種方式帶來的好處有如下幾點:
- osd和客戶端直連:網絡支持的併發鏈接數是有限的,若是存在中心節點則在集羣規模變大時中心節點的鏈接數容易超過限制。去中心化則使用ceph客戶端能夠直接與osd相鏈接,這樣提升了總體的性能和整個系統的併發量。
- osd成員和狀態:osd加入集羣后會報告它自身的狀態,在最底層,用up,down來表示osd是否正常運行,down,in這兩種狀態表示osd存在問題。若是osd沒有在運行(好比:崩掉了),那它就沒法告之監視器它處於down狀態,而監視器會定時ping osd以確保它們還在運行。不過,ceph還容許osd受權鄰近的其它osd來判斷其是否處於down狀態,並更新集羣運行圖並報告給監視器,這樣監視器能夠以輕量級狀態運行。
- 數據清洗:做爲維護數據一致性和清潔度的一部分,osd能夠把pg裏面的對象元數據和另外一個osd上面的pg裏的副本相比較來清洗pg裏面的對象。清洗任務用來捕獲osd上的bug或文件系統錯誤。osd還能夠一個比特位一個比特位對比的方式來執行深度清洗,以找出輕度清洗時沒有發現的硬盤的壞扇區。
- 複製:osd採用crush算法來計算對象副本應該存儲的位置。在寫數據的過程當中,客戶端使用crush算法來計算對象應該存在哪,將對象映射到一個pool和pg,而後經過crush運行圖來定位主osd。客戶端將對象寫入到主osd上的pg,而後,主osd經過crush運行圖來定位第二和第三副本所在osd,將對象複製到這些osd上的pg裏面,最後再回應客戶端對象保存成功。示意圖以下:
動態集羣管理
ceph設計的關鍵點是自主自治,下面就介紹下crush是怎麼作到讓現代雲存儲服務實現保存數據,從新平衡集羣以及是如何從失敗狀態中恢復的。
關於Pool
ceph有一個概念叫池(Pool),是對對象的邏輯分區。客戶端從監視器獲取一份集羣運行圖,而後往池裏面寫入對象。池的大小或者說是副本數量,crush規則集和pg的數量共同決定了ceph將怎樣存儲數據:
池的集合至少有如下幾個參數:
- 對象的全部權/訪問權
- pg的數量
- 用到的crush規則集
PG和OSD的映射關係
每一個池都有若干個pg,crush動態地映射pg和osd的關係,當客戶端要寫入對象時,crush算法會把每一個一對象映到到一個pg。這種將對象映射到pg的方式爲osd和客戶端之間創建了一層間接的關聯關係。ceph集羣必須支持節點的增長或減小並從新平衡對象的分佈,若是客戶端知道osd具體保存有哪些對象就會致使它們之間有強耦合的關聯。相反,crush算法經過將每一個對象映射到一個pg,每一個pg映射到一個或多個osd,使得當有新osd加入或上線時ceph就能夠方便的動態的從新平衡數據的分佈。
客戶端經過集羣運行圖,利用crush算法能夠計算出某個具體對象應該保存在哪一個osd上:
計算PG的id
當客戶端從監視器獲取到最新的集羣運行圖時,它就知道了全部監視器,osd和元數據服務器的信息,可是這時它並不知道對象存儲的位置。對象存儲的位置須要經過計算得出。
只須要輸入對象id和池的信息,客戶端使用對象名稱,一個哈希值,池中pg的數量和池的名稱就能計算出pg,如下是計算pgid的步驟:
- 客戶端輸入池id和對象id
- ceph計算出對象id的哈希值
- 使用哈希值對pg的數量取模定位到一個pg的id(如58)
- 經過池的名稱獲得池的id(如「livepool" = 4)
- 將池的id放在pg的id前面(如4.58)
計算對象存儲的位置比經過一系列會話去查詢要快得多,crush算法容許客戶端來計算對象應該存儲在哪,這樣客戶端能夠直接鏈接保存對象的主osd。
互聯和子集
osd相互之間除了會有心跳機制,還會進行互聯,即全部osd會對每一個pg中的全部對象的狀態進行協商達成一致。實際上,osd會向監視器報告互聯過程當中出現的失敗,互聯這個功能一般會本身修復失敗,可是也有可能一直不能修復,關於這一點請參見疑難解答部分。
ceph設計成至少保存對象的兩個副本,這是對數據安全的最低保證。爲了高可用目標,一個ceph集羣只有保存兩個以上對象的副本時才能以degraed狀態運行。
咱們沒有對osd進行1,2,3這樣的命名,而是使用了primary,secondary之類。按照約定,primary是運行集(Acting Set)中的第一個osd,爲上面的每個pg負責與其餘osd進行互聯協商,而且負責接受客戶端寫對象的請求。
對於那些負責同一個pg的osd集合咱們稱之爲運行集(Acting Set)。
運行集中的osd並不老是up狀態,當一個運行集是up狀態時,它就變成了在線集(Up Set)的一部分。在線集是一個重要的特性,由於ceph能夠在一個osd出問題時將pg從新映射到其餘osd節點。
重平衡
當ceph集羣中新增了一個osd節點的時候,集羣運行圖會進行更新,這樣一來就改變了對象存儲的位置,集羣會進行重平衡,將一部分pg轉移位置。但並非全部pg都會進行遷移,即便會發生重平衡,crush算法仍然是比較穩定的,不少pg仍然會留在原來的位置,每一個osd都將騰出一些空間,也不會對新加入的節點形成負載問題。下圖是一次重平衡過程:
數據一致性
經過對比pg和它的副本里的對象元數據,osd能夠在pg裏清洗對象,這一點在前面有講過。
糾刪碼
若是糾刪碼池使用K+M塊數據塊來存儲對象,那它會將對象分紅K塊數據塊和M塊編碼塊。池的大小配置成K+M的話就可讓每塊數據保存到運行集中的一個osd上,塊的序號保存在對象的屬性裏。
若是一個糾刪碼池採用了5個osd(K+M=5),那它最多能夠接受丟失2個osd(M=2)
讀取和寫入校驗碼數據塊
當一個包含ABCDEFGHI的對象NYAN寫入到池中時,糾刪碼函數會把數據內容切分紅3個數據塊:ABC,DEF,GHI。若是數據內容的長度不是K的整數倍將會進行補齊,函數還會建立兩個校驗碼塊:YXY和GQC。每一個塊保存在運行集中的一個osd上。數據塊以對象的形式保存,而且對象名稱相同(NYAN)。數據塊的序號則保存在對象的屬性中(shard_t)。
若是塊2和5丟失了,從糾刪碼的池中讀取對象時,解碼函數會讀取1,3,4三塊數據:BC,GHI,YXY,而後重構出對象的原始內容:ABCDEFGHI。以下圖所示:
寫過程被中斷
在糾刪碼池中,在線集(up set)中的主osd(primary osd)負責接收全部寫請求,負責將數據編碼成K+M塊而後發送給其餘osd,同時也負責維護一份權威版本的pg日誌
下圖示例了一個以K=2,M=1的方式建立的pg,分佈在三個osd上面(osd1,osd2,osd3):有一個對象編碼後分塊保存在這些osd上面:d1v1,d2v2,c1v1,每一個osd上面的pg日誌都是相同的。
osd1是主osd,負責接收整個寫操做,這個操做將替換掉整個原有對象而不僅是對象的一部分,即Version2將替換掉Version1。osd1將對象編碼成三個塊:d1v2保存在osd1,d2v2保存在osd2,c1v2保存在osd3。每一塊都會發送到相應的osd,包括主osd。當一個osd接收到指令要求寫入數據塊時,也會建立一份pg日誌來記錄本次變動。好比只要osd3保存好了c1v2,它就會在日誌中增長一項entry(epoch:1, version:2)。由於osd都是異步工做的,有些塊可能還在傳輸過程當中時另外一些可能已經落盤保存好了。以下圖:
若是一切順利進行,每一個osd都會確認數據塊寫入成功,而後日誌中'last_complete'指針就能夠從1,1指向1,2。以下圖:
最後,用來保存以前的那個舊的數據塊的文件就要以移除掉了,最終以下圖所示:
可是也有可能發生意外,發果osd1下線了而d2v2仍然在傳輸中,那這個對象的第2個版本就只寫了一部分:osd3有一塊數據但仍然不足以還原完整對象。這時就丟掉了兩個數據塊:d1v2,d2v2,而K=2,M=1要求至少有兩個數據塊可用才能重建第三塊。假設osd4變成新的主osd,並從日誌中查找到last_complete指針指向(1,1),而後將這個指針做爲新的權威日誌的頭部。以下圖所示:
osd3就會發現它上面日誌的entry(1,2)與osd4上面的權威日誌不匹配,因此它會丟棄c1v2數據塊。數據清洗任務將會經過解碼函數重建出d1v1塊並保存到osd4上面。以下圖所示:
緩存層
緩存層可讓客戶端體驗更好的io性能,你可使用一組相對快但比較貴的存儲設備用來用於緩存層,而使用另外一組相對較慢但更便宜的設備來作爲比較經濟的存儲層。緩存代理負責何時將緩存中的對象刷新到後端存儲,因此緩存層和後端存儲層對於客戶端來講是透明的。以下圖:
擴展ceph
你能夠經過建立共享對象類(Ceph Classes)來擴展ceph。ceph從osd class dir動態加載.so文件。若是你想本身實現一個類,你能夠設計新的對象方法來調用本地方法,或者其餘的類方法。
在進行寫操做時,ceph類會調用本地方法或類方法,對輸入的數據執行一系列操做而後產生一個寫事務的結果。
在進行讀操做時,ceph類會調用本地方法或類方法,對輸出的數據執行一系列操做而後將數據返回給客戶端。
ceph類示例:若是ceph做爲內存管理系統的存儲,能夠對輸入的圖片進行大小和比例的剪裁,嵌入一個不可見的版權說明或水印來保護版權,而後將修改過的圖片保存到ceph。
ceph集羣總結
ceph存儲集羣就像有機體同樣是動態的,不少存儲系統不能很好地利用cpu和內存,而ceph能夠。從心跳,互聯,重平衡集羣或者從失敗中恢復,ceph利用了osd的計算能力來替客戶端作了不少工做。當涉及到硬件推薦和網絡配置時,能夠回顧一下前面的概念來理解ceph是怎麼利用計算機資源的。
ceph協議
ceph客戶端使用原生協議來與ceph集羣通訊。ceph將這些方法打包成librados庫,這樣你就可使用它來建立本身的客戶端,下圖是它的基本結構:
原生協議和librados
現代的應用程序須要一個有異步通訊的能力的簡單的對象存儲接口,而ceph正好能提供這樣的接口,這些接口提供了直接的,可並行訪問對象的能力:
- 對池的操做
- 快照和寫時複製
- 讀寫對象-包括讀寫完整對象,字節範圍,追加或截斷。
- 建立和更新對象屬性 XATTRs
- 建立和更新 key/value對
- 混合多種操做和雙重確認語義
- 對象分類
對象監視和通知
客戶端能夠向主osd註冊一個對象的監聽器並維持一個會話,客戶端也能夠發送通知消息和載荷給全部watcher,並能夠接收watcher的消息。經過這些方式,客戶端可使用任何對象做爲同步或通訊channel。
數據條帶化
存儲設備都存在吞吐量限制,這就影響了存儲性能和伸縮性。因此通常的存儲系統都支持條帶化,即將數據分紅若干連續塊分別存儲到不一樣的設備,這樣來提升吞吐量和性能。經常使用的條帶方式有RAID,ceph的條帶化像RAID0,或是一個條帶卷。ceph的條帶化達到了raid0的吞吐量、n路raid鏡像的可靠性和快速恢復能力。
ceph提供了三種客戶端類型:block device,Filesystem,ObjectStorage,客戶端須要本身負責將用戶數據轉換成多個對象存儲到ceph集羣裏。
最簡單的條帶化方式是一個對象一個對象地寫入條帶數據,客戶端持續往對象寫入條帶單元的數據直到達到對象所容許的最大值,而後建立新的對象來繼續保存剩下的條帶單元數據。這種方式對於小的塊存儲,s3或Swift對象和cephfs的文件是有效率的,可是尚未最大化的利用ceph的分佈式pg的能力,因此也不能提高多大的性能。
若是你須要存儲大的塊,對象或文件等,採用多對象集合條帶化的方式能夠獲得可觀的性能提高。客戶端將條帶單元大小的數據併發寫入相應的條帶對象。由於每一個對象對應到不一樣的pg從而對應到不一樣的osd,因此每次併發寫操做都能達到最大的寫速度。寫入到單個磁盤會受限於磁頭的速度,而將寫操做分佈到多個磁盤能夠減小每一個磁盤的總尋址次數,從而能夠結合多個磁盤的吞吐量達到較快的寫速度。
下圖展現了客戶端數據在對象集(object set 1)中的條帶化過程,對象集中有四個對象,條帶單元數據按順序寫入到這四個對象,每寫一輪客戶端都會判斷一下對象集是否已滿,沒滿則繼續從第一個對象開始寫數據,若是滿了則建立另外一個對象集(object set 2),而後按一樣的方式寫入數據。
有三個重要變量決定了ceph如何條帶化數據:
- 對象大小: ceph集羣中有對象的最大大小限制,這個大小必須能容納多個條帶單元的數據,而且應該是條帶單元的整數倍。
- 條帶帶寬:條帶有一個單元大小的配置,客戶端將數據按單元大小進行分塊。
- 條帶數量:客戶端每次按照條帶數量來決定將多少個條帶單元寫入到多少個對象中。這些對象稱之爲對象集,當數據寫入到最後一個對象後,客戶端又從集合中第一個對象開始寫。
重要:在上生產環境前對你的條帶配置進行性能測試,一旦條帶化數據寫入到對象後就不再能修改這些參數了。
ceph客戶端
ceph客戶端包含幾種接口:
下圖是一個高層架構視圖:
ceph對象存儲
對象存儲radosgw是一個網關服務,它提供了一套restful風格的api來存取對象和元數據。它是基於ceph集羣,有本身的數據格式,維護本身的用戶數據庫,認證和訪問控制。rgw使用了統一的命名空間,因此你可使用openstack swift兼容api或者亞馬遜s3兼容api。好比,你能夠經過s3接口寫入數據,而後經過swift接口讀取數據。
ceph塊設備
ceph塊設備將一個塊設備映象條帶化成多個對象,每一個對象都分散到一個pg中,而pg又分散到不一樣的osd上。
這種精簡的,可快照的ceph塊設備對於虛擬化和雲計算是頗有吸引力。在虛擬機場景,人們常用Qemu/KVM中的rbd網絡存儲驅動部署ceph塊設備,其中宿主機採用librbd向客戶機提供塊設備服務。許多雲計算堆棧使用libvirt和管理程序集成。你能夠採用精簡的的ceph塊設備搭配Qume和libvirt來支持openstack和cloudstack,構成一套解決方案。
ceph文件系統
ceph文件系統在ceph集羣的上面提供了一套posix兼容的接口,cephFS裏的文件映射爲ceph集羣裏的一個對象。ceph客戶端將cephfs掛載成一個內核對象或做爲面向用戶的文件系統(FUSE)。以下圖:
cephFS服務包括了與ceph集羣部署在一塊兒的mds(ceph metadata server),mds的目的是在高可用的元數據服務器上保存全部文件系統元數據(目錄,文件擁有者,訪問模式等),這些元數據在內存裏也有一份。mds的意義在於對那些簡單的文件系統相關操做(如ls,cd)沒必要要去浪費osd的資源。將元數據和數據分開意味着ceph文件系統能夠在不浪費集羣資源的狀況下提供高性能的服務。
cephFS將數據和元數據分開,元數據保存在mds,文件數據保存在一個或多個對象中。cephFS的目標是posix兼容,ceph-mds能夠以單進程形式運行,或者它也能夠分佈到多個物理機上運行,這樣也是爲了高可用和高伸縮性:
- 高可用:有額外的mds在一旁待命,這樣一旦活動的ceph-mds失敗就能夠取而代之。這是很容易的由於全部數據,包括日誌,都是保存在rados上的。這個主備的轉換過程由ceph-mon自動完成。
- 伸縮性:能夠有多個ceph-mds處於活動狀態,它們將文件夾樹切分紅多個子樹,有效地平衡活動服務器的負載。
能夠將standy和active組合在一塊兒,好比運行3個活動的ceph-mds來提供伸縮性,一個待命例程來提供高可用。