您好,登錄后才能下訂單哦!
本篇文章為大家展示了如何實現ceph原理分析,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
Ceph是一種開源的軟件定義存儲系統,誕生于2004年,最早致力于開發下一代高性能分布式文件系統的項目。Ceph可以部署在任意x86服務器上工作,具有良好的擴展性、兼容性和可靠性。它能對外提供文件系統服務(cephfs)、塊服務(rbd)和對象存儲服務(rgw),是一種統一存儲系統。Ceph架構支持海量數據存儲,集群可以擴展至PB容量,系統本身無熱點數據,數據尋址依賴計算而不是查找,并能做到數據狀態自維護,數據自修復,是一款優秀的分布式存儲系統。
圖 1 ceph全景
Ceph架構主要包含了:Rados集群,librados接口層,rgw、rbd和cephfs這三種存儲服務。
Rados集群:Rados是Ceph系統的核心,包含了分布式集群管理和數據管理,集群的擴展性和高可用性是在這里體現的。主要的組件有monitor、osd和mds。Monitor是集群的關鍵服務,它保證了集群元數據的一致性和集群的可服務性。Osd是ceph的數據服務,它負責了業務數據的落盤,數據狀態的監控,數據狀態恢復,數據的遷移和恢復等流程。Mds是cephfs的元數據服務,維護文件系統的超級塊信息,目錄結構,文件信息等。一般如果不使用cephfs,是可以不用部署mds的。
librados接口層:統一封裝的接口層,提供集群連接接口,pool創建接口,obj讀寫接口等,作為基礎庫提供給上層調用,比如librbd、libcephfs和librgw。第三方的應用可以直接調用librados對ceph做二次開發。
客戶端:ceph客戶端包括rbd、rgw、cephfs這三種類型,同時也包括librbd、libcephfs和librgw這些開發庫。對外提供存儲服務,比如rbd可以導出scsi塊設備,cephfs可以mount到Linux主機上做為文件系統,也可以通過cifs/nfs導出為網絡文件服務,rgw對外直接提供s3或者swift對象存儲服務。
Monitor服務是ceph的核心服務之一,它主要作用是為整個集群提供全局的配置和系統信息。Ceph集群其實是體現在Monitor集群上的,Monitor是一個獨立部署的服務,多個Monitor組成高可用集群。Monitor采用paxos算法保證集群數據的一致性,Monitor所管理的數據包括:
1、 Monitor Map:包括集群的fsid,所有的monitor的ip和端口,以及epoch
2、 OSD Map:包括集群的fsid,所有osd狀態及監聽地址,pool的信息及pg數等
3、 MDS Map:包括所有的mds服務的列表和狀態,data pool和metadata pool
4、 PG Map:所有pg的信息,包括狀態、version等
5、 CRUSH Map:一個樹形結構,包括存儲設備,故障域等
Monitor通過心跳這種方式來獲得OSD服務的工作狀態,根據這種狀態的變化更新相應的位圖。
首先是OSD之間會有心跳檢查,OSD會檢查osd_heartbeat_min_peers個OSD服務,peer osd其實是指的osd相鄰的osd服務,默認是10個。這些相鄰的osd服務首先是包含同一個pg的osd列表,這個是從pg_map上獲取,如果得到的osd列表超過osd_heartbeat_min_peers個就丟棄,不足的就補上當前osd周圍狀態up的osd進來。
檢查過程是每osd_heartbeat_interval秒就檢查一次peer端的osd,默認是6秒。如果peer端osd在osd_heartbeat_grace后沒回復,默認20s,則標記這個osd狀態為down。
圖 2 osd peer間心跳
在不同故障域之間osd的狀態變化,monitor可能不會第一時間感知到,這里設置了不同故障域的reporter個數,默認是1
圖 3 不同故障域的檢查
圖3所示,osd1和osd2分屬于兩個不同的故障域。
如果一個osd不能和peer內的所有osd做心跳了,則會向monitor申請最新的osd map。超時時間為osd_mon_heartbeat_interval默認30s。
Monitor如果在mon_osd_report_timeout內收不到osd的消息,則會設置osd為down,mon_osd_report_timeout默認為900s。
正常情況下osd每隔osd_mon_report_interval_min,(最短間隔時間默認為5s)會向monitor報告一次事件,事件包括start剛啟動、osd故障、up_thru的變化等。osd向monitor報告的最長時間為osd_mon_report_interval_max,默認為120s。意思是說120s無論osd有沒有狀態變化都需要向monitor報告。
圖 4 osd向monitor報告
OSD(object storage daemon)負責Ceph集群的數據讀寫,同時也負責向Monitor報告監控的OSD的狀態。管理數據的遷移,副本,數據平衡,數據恢復。Ceph集群數據管理的核心服務,通往磁盤的數據通道。
OSD主要包含了兩個主要組成部分,一個PG,另一個是ObjectStore。PG(placement group)是Ceph的數據管理的基本邏輯單位,參與數據讀寫,數據遷移,數據恢復等和數據相關的全部流程。ObjectStore是負責向本地存儲讀寫的模塊,現在常用的是filestore和bluestore,當前onestor版本使用的是filestore。Filestore實際上是操作的本地文件系統,將業務最終寫到本地磁盤的文件中,默認是使用xfs文件系統。Bluestore是直接操作的裸盤,數據直接通過BIO下到盤上,性能相較于filestore有較大提升,Ceph的最新版本默認采用是Bluestore。
圖 5 數據讀寫過程
數據要存儲在Ceph上需要經歷幾個主要步驟:
1、 Client需要獲得Monitor最新的cluster map,得到map后確定osd的信息
2、 對象到pg的hash,具體為對待寫的object id做hash,得到的hash值,再對當前pool的pg_num取模,最后得到該對象所在的pg id。
pg_id = hash(object_name) % pg_num
然后再將pool id加到hash值之前,比如4.f1,4就是pool id,f1是上面算出的hash值,這兩部分構成一個pg id。
3、 pg到OSD的映射,數據最終需落盤,所以pg得映射到一個OSD上。這個映射過程采用的Ceph自己獨有的CRUSH算法,通過計算選擇一個合適OSD。CRUSH本質是一種偽隨機算法。找到OSD后,Client直接與OSD通信,建立網絡連接,將數據發送到OSD服務處理。
4、 OSD最后把收到的數據投遞給ObjectStore,由它完成向本地存儲寫入的過程。同時完成主從OSD的數據落盤。
OSD的數據寫入過程滿足數據的強一致性,待所有數據落盤才向上返回。
圖 6 主從OSD寫入過程
1、 Client先將寫請求發到主OSD上。
2、 主OSD在收到Client請求后,立即向從OSD發送寫請求,同時也寫入主OSD的本地存儲上。
3、 主OSD收到從OSD寫入成功的ack,再確認自己處理正確,最后再返給Client寫完成ack。寫過程中必須等到所有的OSD的寫成功返回才能向Client返回寫操作成功的消息。
Pool是一種邏輯上存儲資源池,Ceph對外提供的存儲服務,資源都是從Pool中劃分提供的。Pool分兩種一種是副本模式,一種是糾刪碼模式。一個Pool是由許多PG構成的。Pool的信息保存在osd map中。
PG是對象數據的集合,同一個集合內的對象應用相同的存儲策略。比如對象的副本都會存放到相同的OSD列表中。一個對象只屬于一個PG,一個PG包含多個對象,一個PG會存放到多個OSD上,一個OSD會承載多個PG。
圖7表示了一個pool是雙副本,對象t1是怎么分布到pg 1.3e的。
圖 7 pg與osd對應關系
CRUSH(control replication under scalable hash)算法是Ceph內部中重要的尋址算法,它主要解決對象到盤的尋址過程。同時由于是通過計算得出,因此集群不需要查詢地址,所以也就沒有中心節點的產生,極大的減少了元數據的體量。CRUSH可以將數據盡量的分散到各個存儲上。
CRUSH算法主要使用的場景:數據io的時候,創建pool的時候,osd狀態up/down,osd的添加和刪除。3.2節所描述的,CRUSH主要是解決PG是如何映射到OSD列表的問題。用函數表示就是:
crush(pg.x) -> (osd.1, osd.2, osd.3,….osdN)
圖 8 CRUSH Map
CRUSH map可以認為是數據中心的抽象,它的目的是尋找到合適的位置存放數據副本。CRUSH內容包括了組織結構Hierarchical CRUSH Map,副本選擇規則Placement Rules以及容器Bucket。
層級化CRUSH Map,邏輯上看組織結構是個樹形結構。包含device和bucket,device一般為osd服務作為葉子節點。bucket作為設備的容器,一般為CRUSH Map中的普通節點。bucket的類型有osd(device),host,chassis,rack,row,pdu,pod,room,datacenter,region,root,這些類型描述了CRUSH Map中的存儲位置。每個bucket包含多個device。
Bucket Weight,權重是用來描述存儲能力的指標。1T大小表示為1,采用雙精度數表示。Bucket的權重大小是包含子bucket或device的權重大小。
Placement Rules決定了對象副本選擇規則,它定義從哪些bucket或是device里去選擇。這樣可以定義不同的pool可以從不同的磁盤選擇存放位置。
表格 1 bucket定義
# buckets host cvknode146 { id -2 # do not change unnecessarily # weight 2.160 alg straw2 hash 0 # rjenkins1 item osd.1 weight 1.080 item osd.3 weight 1.080 } host cvknode145 { id -3 # do not change unnecessarily # weight 2.160 alg straw2 hash 0 # rjenkins1 item osd.0 weight 1.080 item osd.4 weight 1.080 } host cvknode144 { id -4 # do not change unnecessarily # weight 2.160 alg straw2 hash 0 # rjenkins1 item osd.2 weight 1.080 item osd.5 weight 1.080 } rack rack0 { id -7 # do not change unnecessarily # weight 6.480 alg straw2 hash 0 # rjenkins1 item cvknode145 weight 2.160 item cvknode144 weight 2.160 item cvknode146 weight 2.160 } root partition0 { id -5 # do not change unnecessarily # weight 6.480 alg straw2 hash 0 # rjenkins1 item rack0 weight 6.480 } # rules rule partition0_rule { ruleset 1 type replicated min_size 1 max_size 10 step take partition0 step chooseleaf firstn 0 type host step emit } rule partition0_ec_rule_1 { ruleset 2 type erasure min_size 3 max_size 20 step set_chooseleaf_tries 5 step set_choose_tries 100 step take partition0 step chooseleaf indep 0 type host step emit } |
表1中描述的是CRUSH Map的定義的Bucket,用樹形圖表示就是:
圖 9 crush map圖形化
圖9所示,root作為crush map的入口,定義了bucket rack0,其中包括3個host,每個host包括了兩個device osd。bucket的定義了隨機選擇算法為straw2,hash算法為rjenkins1。這里的hash算法是用來計算隨機值,隨機選擇算法是根據隨機值判定選擇OSD。
表1中所定義的選擇規則是partition0_rule和partition0_ec_rule_1。規則原型如下:
rule <rulename> { ruleset <ruleset> type [ replicated | erasure ] min_size <min-size> max_size <max-size> step take <bucket-name> [class <device-class>] step [choose|chooseleaf] [firstn|indep] <N> <bucket-type> step emit } |
ruleset:當前規則的id
type:pool的存儲模式
min_size:如果Pool的副本數小于min_size則不使用這個規則
max_size:如果Pool的副本數大于max_size則不使用這個規則
step take <bucket-name> [class <device-class>]:
選擇一個bucket,一般是root類型bucket,以這個為查詢的輸入,遍歷這顆樹。同時也可而已指定自定義的設備類型。
step choose firstn {num} type {bucket-type}:
深度優先選擇num個bucket-type類型的子bucket。
l If {num} == 0, choose pool-num-replicas buckets (all available).
l If {num} > 0 && < pool-num-replicas, choose that many buckets.
l If {num} < 0, it means pool-num-replicas - {num}.
如果num為0則選擇和pool副本數一樣的,num大于0小于pool的副本數,則返回num個副本數,如果num小于0,則返回pool副本數減num的個數。
step chooseleaf firstn {num} type {bucket-type}:
和上一條規則一樣,區別在于chooseleaf是選擇葉子節點,一般就是osd。
step emit:
輸出選擇結果。
現在有了crush的組織結構CRUSH Map和選擇規則Placement Rules,從bucket中選出合適的設備是采用隨機算法來做具體的選擇。當前CRUSH所支持的隨機算法有:
表格 2 隨機選擇算法
Uniform | 適用于每個item權重相同,且很少添加或刪除,item的數量比較確定。 |
List | 以鏈表保存item,包含的item可以是任意權重,但是會造成某些節點被選中的概率變大。 |
Tree | 采用2分查找樹,包含大量item的情況下可以快速查找,但是會造成某些節點被選中的概率變大,而在節點刪除添加移除和重新修改權重會引入額外組織變動開銷,查找速度O(logn)。 |
Straw | 相對List和Tree是比較公平的算法,每個節點都有公平競爭的機會,而且權重越大的節點被選中的機會越大。 |
Straw2 | Straw的改進算法,減少了在節點刪除移動的時候數據遷移量。 |
具體描述Straw算法,提供各個bucket盡量公平的選擇機會,權重越大選中的概率越高。執行過程其實遞歸遍歷bucket,找到合適device。如果權限大就盡量找權限大的,如果權限一樣則隨機返回。
圖 10 straw代碼片段
如代碼所示:
1、 crush(pg_id, osd_id, r) => draw,r為常數,運算次數
2、 ( draw &0xffff ) * osd_weight => straw
3、 得到最大的high_draw,返回該item
其中draw就是隨機數,然后用draw乘以權重得到一個簽值,選中最大簽值的OSD。要保證不能每次都選中權重最大那個,隨機數的產生就很重要。
圖 11 rjenkins hash算法
將3組數據傳入進行混合攪拌,盡量得到一個隨機值。可以看到只要傳入的值是相同的,得到隨機值也是相同的,所以CRUSH是一個偽隨機的算法。
參考源碼src/crush/mapper.c,入口函數crush_do_rule
ObjectStore是Ceph系統落盤前的最后一個模塊,它負責保證業務數據可以安全可靠高效的IO。ObjectStore定義事務操作,具體的本地存儲必須實現這些操作。ObjectStore目前包括4種本地實現:
1、 FileStore:H、J版本使用較多的本地存儲,采用文件系統做為對象讀寫的方式。
2、 BlueStore:最新L版本支持的本地存儲,未來Ceph的默認方式,拋棄掉文件系統直接操作塊設備,性能最好。
3、 KStore:使用KV存儲系統作為本地存儲。
4、 MemStore:數據和元數據都保存在內存中,主要用于測試和驗證。
目前用于生產環境的是FileStore和BlueStore。
FileStore默認使用xfs文件系統保存數據。利用文件系統POSIX接口實現ObjStore的接口,每個對象在底層是以文件存在。
圖 12 filestore結構
FileStore包含FileJournal和DBObjectMap兩個模塊,FileStore為了提高ObjectStore寫事務處理能力和原子性引入了FileJournal。它相當于數據庫的WAL(write ahead log),為了保證每個寫事務的完整性。它會使用direct io方式寫到journal日志里,完成后再將事務提交到FileStore的隊列中繼續完成寫操作,如果中途有發生crash,OSD在做recovery的時候會將日志恢復出來。
FileStore寫數據順序是,先寫journal然后再寫盤上。Journal寫完后會返回給上層,但是要能read ready還是要等到數據落盤后才行,不過在大量小io隨機寫場景性能還是不錯。FileStore由于先寫日志再寫盤,所以有個寫放大的問題。
DBObjectMap是專門用來管理對象的屬性的模塊,有兩種實現xattr和omap。xattr是用文件系統的擴展屬性實現的,受限于文件系統擴展屬性的長度限制,適合小量數據存放。omap是采用leveldb k-v鍵值存儲實現,如果屬性大小超過xattr的限制,則可以存放到omap中。
圖 13 bluestore整體結構
Bluestore為解決filestore在寫數據前先寫journal產生的寫放大,并針對ssd做了相應的優化。Bluestore直接操作裸盤,盡可能的避免文件系統(xfs、ext4)的開銷。操作裸盤則盤空間管理由allocator(默認是BitmapAllocator)處理。Bluestore在io過程中產生的元數據,元數據則存放到rocksdb kv數據庫中。rocksdb存數據依賴文件系統,但是rocksdb將底層系統相關的抽象為env,用戶程序只需要實現相應的接口就可以提供底層的系統的封裝。Bluestore實現了BlueRocksEnv,并實現了Bluefs支撐BlueRocksEnv。Bluefs的日志和數據文件都是保存在裸盤上,和用戶數據共享裸盤設備,也可以分開指定不同設備。
圖 14 osd設備數據分區
osd目錄分區:默認占用100M,默認掛載xfs文件系統。提供基本的描述信息,包括whoami(osd編號),osd的type,osd的魔術字,block塊設備入口等。
Block dev label分區:默認占用4K。存儲bluestore_bdev_label_t結構體信息,包含osd_uuid,塊設備size,設備描述信息,創建時間等。
Bluefs supper block分區:默認占用4K。存儲bluefs_super_t結構體信息,包含osd_uuid,version和block_size等。
DB數據分區:默認占用MAX[1G,塊設備總大小的4%],保存DB數據和日志數據。
用戶數據分區:默認占用剩余空間,存放用戶業務數據。
元數據映射關系:
圖 15 元數據映射關系
一個對象對應一個onode,一個onode包含多個extent,多個extent存放在一個或者多個blob里,每個blob又對應到多個pextent,就是具體的物理塊,這樣就完成了extent到pextent的映射。
BlueStore讀過程比較簡單,如果有預讀標志則從cache里讀,如果沒命中則需要從盤上讀出來并且添加到cache中。
Bluestore寫過程比較復雜,大致分為大寫和小寫。根據寫入數據長度來確定是小寫還是大寫,通過對min_alloc_size(blob的最小分配大寫默認64K)取模,如果小于64K為小寫流程,如果大于64K則為大寫流程。
圖 16 寫場景
小寫分為覆蓋寫和非覆蓋寫,其中非覆蓋小寫和大寫沒有寫懲罰,先寫數據然后改元數據。覆蓋寫場景會產生WAL日志,先要完成WAL日志處理落盤后,再寫入業務數據。
整體來說性能比filestore提高不少。
Ceph系統中承擔數據IO和數據恢復的基本邏輯單元叫PG(Placement Group),PG是Ceph中數據載體。可以理解PG為一個目錄或者集合,包含了多個對象。
PG有自己的狀態,PG健康度出現異常,狀態會發生變遷,數據也會發生遷移。
active+clean:PG的健康時的狀態。
Degraded:降級狀態,如果是雙副本的配置,有個osd掛掉了,PG就會進入這種狀態。這種情況下PG還是可以提供IO服務的。
Recovery:一個osd出現故障下線了,但這時pg還是可讀寫的,當故障osd啟動后,它所保存的數據比其他osd版本要舊這個時候就會產生recovery,保證數據一致。
Remapped:如果osd下線是由于硬盤故障,這個時候就是永久性故障,需要再分配新osd做重新映射。選中新osd后,數據還是為空的,需要從正常的osd上將數據全量拷貝到新osd上,所以狀態一般是remapped+backfilling。
Peered:出現這種狀態,是由于故障的osd數量過多,造成了pg不能讀寫了。這個狀態可以理解為正常的osd在等待其他副本osd上線。
Peering過程是一個PG對應的一組OSD的狀態達到一致的過程,PG達到active時,peering過程就完成了,但是PG對應的OSD上的數據并不一定完全一致。
PG發生的場景:
n 系統初始化OSD啟動重新加載PG或者創建PG,會觸發PG發起一次Peering過程。
n OSD故障或OSD增加減少,會導致PG的acting set發生變化,PG也會發起一次Peering過程。
peering概念介紹
1、 acting set和up set
acting set是一個PG活動的一組OSD,該列表是有序的,下標第一個OSD為prime OSD。up set一般與acting set相同。不相同的情況是OSD故障導致,生成臨時PG。這個時候acting set和up set不一致。
2、 臨時pg
原OSDacting set列表中[0,1,2]的主OSD osd.0故障了,crush重新選出的acting set為[3,1,2],但是這個時候osd3并沒有該PG的數據,需要做backfill,這個時候osd3是不能讀的。所以會產生一個臨時PG做為prime,比如通知monitor讓osd1做臨時prime,這個時候up set就為[1,3,2],acting set還是[3,1,2],backfill做完,臨時pg取消,兩個列表就想同了。
3、 Authoritative History權威日志
指的是記錄pg完整順序的連續的操作日志記錄,做為數據恢復的依據。
Peering的過程,基本分為三個步驟
l GetInfo : pg的主osd通過發送消息獲取各個從OSD的pg_info信息。
l GetLog:根據pg_info的比較,選擇一個擁有權威日志的osd(auth_log_shard) , 如果主osd不是擁有權威日志的osd,就去擁有權威日志的osd獲取,獲取后主osd也擁有權威日志。
l GetMissing:拉取其它從OSD 的pg log(或者部分獲取,或者全部獲取FULL_LOG) , 通過本地的auth log對比,來判別從OSD 上缺失的object 信息。以用于后續recovery過程的依據。
l Active: 激活主osd,并發想通知notify消息,激活相應的從osd。
簡單來說peering并不恢復數據,只是將各個osd的狀態統一起來,明確哪些對象需要恢復,為下一步做準備。
Peering完成后,就可以知道是否有數據需要恢復了。恢復的方式有兩種recovery和backfill。
Recovery是就根據PG日志中缺失的記錄來修復不一致的對象。
Backfill是PG通過重新掃描所有對象,對比發現缺失的對象,通過整體拷貝的方式修復。當OSD失效時間過長導致無法根據PG日志記錄來修復,或者新OSD加入導致的數據遷移,這些都會導致Backfill流程。
存儲系統中io路徑復雜,傳統存儲系統一般包括從應用層到內核文件系統、塊設備、SCSI層再到HBA和磁盤控制器,每層都有出錯的可能。因此傳統的端到端解決方案會以數據塊校驗為主來解決。
因為 Ceph 作為一個應用層的應用,這時候如果封裝固定數據塊并且加入校驗數據會導致較嚴重的性能問題,因此 Ceph 在這方面只是引入 Scrub 機制(Read Verify)來保證數據的正確性。
簡單來說,Ceph 的 OSD 會定時啟動 Scrub 線程來掃描部分對象,通過與其他副本進行對比來發現是否一致,如果存在不一致的情況,Ceph 會拋出這個異常交給用戶去解決。
Scrub按照掃描內容不同分為兩種方式:
n 一種叫srub,它只是比較各個對象的副本元數據,來檢查數據一致性。只是檢查元數據,所以讀取和計算的量都比較小,一種輕量的檢查。
n 一種叫deep-srub,它要進一步檢查對象的數據內容是否一致,實現深度掃描,幾乎要掃描磁盤上的所有數據并計算crc32校驗,所有開銷很大,占用系統資源很多。
Scrub按照掃描的方式分為兩種:
n 在線掃描:不影響系統正常業務。
n 離線掃描:需要系統停或凍結業務。
Ceph的Scrub是實現了在線掃描,可不中斷系統業務的前提下執行scrub,但是針對具體某個對象做Scrub,是會鎖定對象的,阻止客戶端對它的訪問,一直到Scrub執行完成才會釋放。
上述內容就是如何實現ceph原理分析,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。