ceph crush算法和crushmap淺析

1 什麼是crushmap

crushmap就至關因而ceph集羣的一張數據分佈地圖,crush算法經過該地圖能夠知道數據應該如何分佈;找到數據存放位置從而直接與對應的osd進行數據訪問和寫入;故障域的設置和數據冗餘選擇策略等。crushmap的靈活設置顯示出了ceph的軟件定義存儲方案。
這裏能夠引入raid相關的概念來對比下:
raid0:又稱爲Stripe,中文名爲條帶,它是全部RAID級別中存儲性能最高的,它的原理就是把連續的數據分散存儲到多個磁盤中,充分利用了每一個磁盤的吞吐,突破了單個磁盤的吞吐限制。
raid1:又稱爲Mirror,中文名爲鏡像,它的主要宗旨是保證用戶的數據可用性和可修復性,它的原理是把用戶寫入硬盤的數據百分之百的自動複製到另一個磁盤上。
raid10:高可靠性與高效磁盤結構,能夠理解爲raid0和raid1的互補結合,相似於ceph中的多副本策略。
raid5:是一種存儲性能、存儲成本和數據安全都兼顧的一種方案,它的原理是不對存儲的數據進行備份,而是把數據和存儲校驗信息存儲到組成raid5的各個磁盤上,當raid5的一個磁盤損壞時,能夠根據剩下的數據和奇偶校驗信息來恢復損壞的數據,相似於ceph中的糾刪碼策略。算法

對導出的crushmap進行反編譯後獲得的內容以下:安全

# begin crush map 選擇存放副本位置時的選擇算法策略中的變量配置
tunable choose_local_tries 0
tunable choose_local_fallback_tries 0
tunable choose_total_tries 50
tunable chooseleaf_descend_once 1
tunable straw_calc_version 1

# devices    通常指的是葉子節點osd
device 0 osd.0
device 1 osd.1
device 2 osd.2

# types    樹形下的多種類型
type 0 osd    # 通常一個osd對應一個磁盤
type 1 host    # 通常host表示是一個主機,即某一臺服務器 
type 2 chassis # 系列
type 3 rack # 機架
type 4 row # 排
type 5 pdu # 
type 6 pod    # 
type 7 room # 機房
type 8 datacenter    # 數據中心
type 9 region    # 區域
type 10 root    # 根

# buckets    軀幹部分 host通常是表示一個物理節點,root是樹形的根部
host thinstack-test0 {
id -2    # do not change unnecessarily
# weight 0.031
alg straw # ceph做者實現的選擇item的算法
hash 0    # rjenkins1 這表明的是使用哪一個hash算法,0表示選擇rjenkins1這種hash算法
item osd.0 weight 0.031
}
host thinstack-test1 {
id -3    # do not change unnecessarily
# weight 0.031
alg straw
hash 0    # rjenkins1
item osd.1 weight 0.031
}
host thinstack-test2 {
id -4    # do not change unnecessarily
# weight 0.031
alg straw
hash 0    # rjenkins1
item osd.2 weight 0.031
}
root default {
id -1    # do not change unnecessarily
# weight 0.094
alg straw
hash 0    # rjenkins1
item thinstack-test0 weight 0.031
item thinstack-test1 weight 0.031
item thinstack-test2 weight 0.031
}

# rules    副本選取規則的設定
rule replicated_ruleset {
ruleset 0
type replicated
min_size 1
max_size 10
step take default    # 以default root爲入口
step chooseleaf firstn 0 type host    # 看以下 解釋1
step emit    # 提交
}

# end crush map

解釋1:
step chooseleaf firstn {num} type {bucket-type}
chooseleaf表示選擇bucket-type的bucket並選擇其的葉子節點(osd)
當num等於0時:表示選擇副本數量個bucket
當num > 0 and num < 副本數量時:表示選擇num個bucket
當num < 0: 表示選擇 副本數量 - num 個bucket

 

2 crush的基本原理

經常使用的分佈式數據分佈算法有一致性Hash算法和Crush算法,Crush也稱爲可擴展的僞隨機數據分佈算法
一致性Hash算法原理:
對一個圓形(圓形能夠是0-2的31次方-1)用n個虛擬節點將其劃分紅n個區域,每一個虛擬節點管控一個範圍,以下圖所示:

T0負責[A, B],T1負責[B, C],T2負責[C,D],T3負責[D,A]
因爲分區是固定的,因此咱們很容易知道哪些數據要遷移,哪些數據不須要遷移。
在每一個節點的存儲容量相等且虛擬節點跟物理節點個數一致時,就會是每一個節點對應一段相同大小的區段,從而能夠達到最佳的數據分佈。服務器

Crush算法原理:
Crush算法跟一致性Hash算法原理很相似,其中的pg就是充當上面所說的虛擬節點的做用,用以分割區域,每一個pg管理的數據區間相同,於是數據可以均勻的分佈到pg上。dom

crush分佈數據過程:
數據x通過hash函數獲得一個值,將該值與pg數量取模獲得數值,該數值便是pg的編號,而後經過crush算法知道pg是對應哪些osd的,最後是將數據存放到pg對應的osd上。其中通過了兩次的映射,一次是數據到pg的映射,一次是pg到osd的映射,因爲pg是抽象的存儲節點,通常狀況下,pg的數量是保持的不變的,不隨着節點的增長或減小而改變,所以數據到pg的映射是穩定的。分佈式

 

3 利用crushmap能夠作哪些事

(1)故障域的設置
ceph中已經定義的故障域有:
# types
type 0 osd # 通常一個osd對應一個磁盤
type 1 host # 通常host表示是一個主機,即某一臺服務器
type 2 chassis # 系列
type 3 rack # 機架
type 4 row # 排
type 5 pdu #
type 6 pod #
type 7 room # 機房
type 8 datacenter # 數據中心
type 9 region # 區域
type 10 root # 根
固然也能夠自定義類型
好比有3臺服務器,設置的故障域爲host,數據冗餘策略爲多副本的2副本策略,則數據會保存到其中的兩臺服務器上,這樣當其中一臺服務器掛掉時,確保還有冗餘數據在另一臺服務器上,保證了數據的可靠性。函數


(2)指定數據存放到指定位置上
好比對於一些私有云來講,能夠劃分ssd的磁盤用以存放鏡像等數據,這樣虛擬機啓動會比較快,對於快照和備份等冷數據則可存放在sata盤中。性能


(3)保證數據儘量的均衡
能夠設定osd的權重,若是隻考慮容量,則通常1T容量權重設爲1.0測試


(4)儘量保證數據不會大量遷移引發性能問題
當有節點故障時須要進行數據均衡時,能夠設定合理的crushmap讓數據的遷移只發生在一個小範圍內spa

4 crushmap實踐

(1)獲取當前crushmap並修改和應用
獲取當前集羣中應用的crushmap文件到一個文件中:ceph osd getcrushmap -o crushmap.txt
上面導出的crushmap.txt是亂碼的,須要進行反編譯來查看:crushtool -d crushmap.txt -o crushmap-decompile
此時就是文本形式了,能夠在這個文件上修改,修改後進行編譯:crushtool -c crushmap-decompile -o crushmap-compiled
而後應用到集羣中:ceph osd setcrushmap -i crushmap-compiled
注意:這樣修改若是想要服務重啓後保持原來的,須要在配置文件的[osd]上加上:osd crush update on start = false,不然啓動時會校驗當前位置是不是正確的位置,若是不是則會自動移動到以前的位置命令行

若是隻是想查看下當前的crush map分佈,能夠用命令行查看:ceph osd crush tree

(2)命令行構建crush map
<1>添加bucket:ceph osd crush add-bucket {bucket-name} {bucket-type}
好比添加一個root類型的名爲default的bucket:ceph osd crush add-bucket default root
添加一個host類型的名爲test1的bucket:ceph osd crush add-bucket test1 host

<2>移動一個bucket:ceph osd crush move {bucket-name} {bucket-type}={bucket-name}, [...]
好比我想將bucket1 test1移動到root類型的名爲default2下:ceph osd crush move test1 root=default2

<3>移除一個bucket:ceph osd crush remove {bucket-name}
好比:ceph osd crush remove test1

<4>添加或移動osd的crush map位置:ceph osd crush set {name} {weight} root={root} [{bucket-type}={bucket-name} ...]
好比我將osd.1設置test1下:ceph osd crush set osd.1 1.0 root=default host=test1

<5>調整osd的權重:ceph osd crush reweight {name} {weight}
好比:ceph osd crush reweight osd.1 2.0

<6>移除osd crush map:ceph osd crush remove {name}
好比:ceph osd crush remove osd.1

<7>建立一個副本策略:ceph osd crush rule create-replicated {name} {root} {failure-domain-type} [{class}] # 低版本沒有這個,好比0.94.10就沒有
好比建立一個故障域級別爲host的副本策略:ceph osd crush rule create-replicated rep_test default host
本身項目中用的建立命令:ceph osd crush rule create-simple rep_test default host firstn # 原型是osd crush rule create-simple <name> <root> <type> {firstn|indep}

<8>給pool指定副本策略:ceph osd pool set <pool-name> crush_rule <rule-name>
好比:ceph osd pool set testpool crush_rule test_rule

(3)建立指定主副本放在host A上,其它副本放在host B上

# rules
rule replicated_ruleset {
ruleset 0
type replicated
min_size 1
max_size 10
step take A
step chooseleaf firstn 1 type osd
step emit

step take B
step chooseleaf firstn -1 type osd
step emit
}

這時能夠用ceph pg dump命令看pg的分佈是不是如咱們所想的那樣分佈。
或者測試數據是否真的落到咱們想要的osd上:
put一個文件命名對象名爲uuu到testpool中去:rados put uuu kk.txt -p volumes
查看該對象是在哪一個osd上:ceph osd map testpool uuu

還有個簡單的方法來設置某個osd做爲主的,某個爲副osd:
假設只有osd.0和osd.1,要將osd.0做爲副本osd,1做爲主osd,則能夠將osd.0的主親和力設置爲0,這樣osd.0就只能作副本osd
ceph tell mon.\* injectargs '--mon_osd_allow_primary_affinity=true'
ceph osd primary-affinity osd.0 0

(4)將ssd磁盤的osd用來放主副本,hdd磁盤的osd用來放副本
思路:能夠建立兩個root類型,一個名爲ssd,一個名爲hdd,而後ssd磁盤的osd移到root=sdd下,hdd磁盤的osd移到root=hdd下,crushmap內容以下:

# begin crush map
tunable choose_local_tries 0
tunable choose_local_fallback_tries 0
tunable choose_total_tries 50
tunable chooseleaf_descend_once 1
tunable straw_calc_version 1

# devices
device 0 osd.0
device 1 osd.1

# types
type 0 osd
type 1 host
type 2 chassis
type 3 rack
type 4 row
type 5 pdu
type 6 pod
type 7 room
type 8 datacenter
type 9 region
type 10 root

# buckets
host A {
id -2    # do not change unnecessarily
# weight 0.031
alg straw
hash 0    # rjenkins1
item osd.0 weight 0.031
}
host B {
id -3    # do not change unnecessarily
# weight 0.031
alg straw
hash 0    # rjenkins1
item osd.1 weight 0.031
}
root ssd {
id -5    # do not change unnecessarily
# weight 0.031
alg straw
hash 0    # rjenkins1
item A weight 0.031
}
root hdd {
id -6    # do not change unnecessarily
# weight 0.031
alg straw
hash 0    # rjenkins1
item B weight 0.031
}

# rules
rule replicated_ruleset {
ruleset 0
type replicated
min_size 1
max_size 10
step take ssd
step chooseleaf firstn 1 type host
step emit

step take hdd
step chooseleaf firstn -1 type host
step emit
}

# end crush map

ceph osd tree的命令執行以下:

[root@test ~]# ceph osd tree
ID WEIGHT  TYPE NAME                UP/DOWN REWEIGHT PRIMARY-AFFINITY 
-6 0.03099 root hdd                                                   
-3 0.03099     host thinstack-test1                                   
 1 0.03099         osd.1                 up  1.00000          1.00000 
-5 0.03099 root ssd                                                   
-2 0.03099     host thinstack-test0                                   
 0 0.03099         osd.0                 up  1.00000          1.00000
相關文章
相關標籤/搜索