前言:
分布式存儲系統需要讓數據均勻的分布在集群中的物理設備上,同時在新設備加入,舊設備退出之后讓數據重新達到平衡狀態尤為重要。新設備加入后,數據要從不同的老設備中遷移過來。老設備退出后,數據遷移分攤到其他設備。將文件、塊設備等數據分片,經過哈希,然后寫入不同的設備,從而盡可能提高I/O並發與聚合帶寬。
在實際場景中如何通過最小數據遷移使得集群恢復平衡,如何分配備份到設備上,使得數據盡可能的安全是很重要的問題。Ceph對普通哈希函數擴展后解決了上述問題,Ceph基於哈希的數據分布算法就是CRUSH。
CRUSH支持副本、Raid、糾刪碼數據備份策略,並受控的將數據的多個備份映射到集群不同故障域的底層設備上。
straw算法
最初提供了四種基本選擇算法:
觀察圖中數據得到,unique執行效率最高,抵御結構變化能力最差,straw算法執行效率相較unique於tree要差,但是抵御結構變化的能力最強。因為數據可靠性最為重要,隨着擴容引入越來越多的設備加上使用時間的推移,集群設備需要經常更換固件,因此目前基本生產環境的Ceph集群都選擇straw算法。
straw算法為每個元素隨機計算一個簽長,選擇簽長最長的元素輸出,簽長越長的元素被選中的概率越大,數據落在上面的概率就越大。straw算法通過累計當前元素與前后元素的權重差值作為計算下一個元素簽長的基准,因此在每次加入或刪除osd時,都會引起不相干的數據遷移。后修改為簽長計算僅與自身權重有關系,避免了這一現象,稱為straw2算法,此算法目前為ceph的默認算法。
cluster map
cluster map是集群層級拓撲結構的邏輯描述形式,其簡單的拓撲如:數據中心->機加->主機->磁盤,因此cluster map采用樹這種數據結構。根節點root是整個集群的入口;所有葉子節點device都是真實的最小物理存儲設備(磁盤);中間節點bucket可以是device的集合,也可以是低級的bucket的集合。
cluster map這種層級關系通過<bucket, items>這樣一張二維表映射,每個bucket,都保存自身所有直接孩子的編號,即items。當items為空時,表明bucket為葉子節點。
簡單圖示如下,最下面的葉子節點device(如磁盤)存放數據,中間是host類型的bucket(物理主機),最上面root是集群入口:
配置示例:
host default_10.10.10.125 { # 類型host,名字為default_10.10.10.125
id -3 # bucket的id,root與bucket的數字標識都為負值,只有device是 非負的數字標識,表明device是承載數據的真實設備。
# weight 14.126 # 權重,默認為子item的權重之和
alg straw2 # bucket的隨機選擇算法,這里用 straw2
hash 0 # rjenkins1 # 使用hash函數rjenkins1
item osd.0 weight 6.852 # osd.0的權重
item osd.1 weight 7.274 # osd.1的權重
}
placement rule
cluster map定義了存儲集群的物理拓撲描述。placement rule完成數據映射,即決定一個PG的對象副本如何選擇的規則,用戶可自定義副本在集群中的分布。
placement rule可含有多個操作,包括以下三種類型:
-
take:從cluster map中選擇指定編號的bucket,系統默認為root類型的節點
-
select:接收take輸入的bucket,從中隨機選擇指定類型和數量的item。
step [choose|chooseleaf] [firstn|indep] <Num> type <bucket-type>
[choose|chooseleaf]:choose操作有不同的選擇方式
- choose選擇出Num個類型為bucket-type的子bucket
- chooseleaf選擇出Num個類型為bucket-type的子bucket,然后遞歸到葉子節點選擇一個OSD設備
[firstn|indep]:ceph有兩種select算法(均為深度優先遍歷)。不同之處在於糾刪碼要求的結果是有序的,因此如果指定輸出數量為4而無法滿足時:
- firstn(多副本):[1,2,4]
- indep(糾刪碼):[1,2,CRUSH_ITEM_NONE,4]
[Num] :
- Num == 0,選出的子buket為pool設置的副本數
- pool副本數 > Num > 0,選出的子buket為Num
- Num < 0, 選出的子buket為pool設置的副本數減去Num的絕對值
[type] :故障域的類型,如果為rack,保證選出的副本都位於不同機架的主機磁盤上,如果為host,則保證 選出的副本位於不同主機上。
如果選中條目因故障、沖突等原因無法使用,則會重新執行select。
-
emit:輸出選擇結果
配置示例:
rule <rulename> {
id [a unique whole numeric ID]
type [ replicated | erasure ]
min_size <min-size>
max_size <max-size>
step take <bucket-name> [class <device-class>]
step [choose|chooseleaf] [firstn|indep] <Number> type <bucket-type>
step emit
}
rule data {
ruleset 0 //ruleset 編號
type replicated //多副本類型
min_size 1 //副本最小值為1
max_size 10 //副本最大值為10
step take default //選擇default buket輸入{take(default)}
step chooseleaf firstn 0 type host //選擇當前副本數個主機下的OSD{select(replicas, type)}
step emit //輸出將要分布的bucket的列表{emit(void)}
}
選擇方式
CHRUSH算法依賴以上的算法(默認為straw2)實現對PG的映射,輸入pg_id、Cluster map、Cluster rule,與隨機因子經過哈希計算,輸出一組OSD列表,即該pg要落在OSD的編號。
但是選出的OSD有可能會出現沖突或過載,就需要重新選擇:
-
沖突:指選中條目已經存在於輸出條目中,如osd.1已經存在於輸出列表中,下一個經計算同樣選出了osd.1,此時需要調整隨機因子,再次計算進行選擇。
-
過載或失效:指選出的OSD無法提供足夠的空間來存儲數據,雖然CRUSH算法理論上可以讓數據在所有device(磁盤)中均勻分布,但實際並非如此:
- 小規模集群,PG數量較少,則CRUSH輸入的樣本容量不夠,導致數據計算分布不均勻。
- crush自身對於多副本模式數據均勻分布做的不夠完善。
ceph引入過載測試reweight可人工干預對OSD的選擇概率,reweight的值設置的越高,則通過測試概率越高,因此可以通過降低過載OSD的reweight和增加低負載OSD的reweight來使得數據均衡。
引入過載測試也可以區分OSD暫時失效和被永久刪除
如果OSD暫時失效(如拔出對應磁盤一段時間,ceph將其設置為OUT),可以將其reweight的值設置為0.000,利用過載測試將其從候選條目中篩掉,進而將其承載的數據遷移到其他OSD。恢復后再將reweight設置為1.000,即可遷回數據(指OSD離線期間產生的新數據)
如果是被永久刪除,那么它會被從候選條目刪除,即便后續再次添加進來,因為cluster map中的唯一編號變化而承載與之前不同的數據,使得集群出現大規模的數據均衡。
學習自:
《Ceph源碼分析》 常濤
《Ceph之RADOS設計原理與實現》 謝型果 嚴軍
https://docs.ceph.com/docs/kraken/rados/operations/crush-map/