1. 介紹
CRUSH 算法通過(guò)計(jì)算數(shù)據(jù)存儲(chǔ)位置來(lái)確定如何存儲(chǔ)和檢索隆檀。 CRUSH 授權(quán) Ceph 客戶端直接連接 OSD 挤牛,而非通過(guò)一個(gè)中央服務(wù)器或代理蔓榄。數(shù)據(jù)存儲(chǔ)、檢索算法的使用补君,使 Ceph 避免了單點(diǎn)故障、性能瓶頸昧互、和伸縮的物理限制挽铁。
CRUSH 需要一張集群的 Map,且使用 CRUSH Map 把數(shù)據(jù)偽隨機(jī)地敞掘、盡量平均地分布到整個(gè)集群的 OSD 里叽掘。CRUSH Map 包含 OSD 列表、把設(shè)備匯聚為物理位置的“桶”列表玖雁、和指示 CRUSH 如何復(fù)制存儲(chǔ)池里的數(shù)據(jù)的規(guī)則列表更扁。
完全手動(dòng)管理 CRUSH Map 也是可能的,在配置文件中設(shè)定:
osd crush update on start = false
2. 編輯 CRUSH Map
要編輯現(xiàn)有的 CRUSH Map:
- 獲取 CRUSH Map茄菊;
- 反編譯 CRUSH 圖疯潭;
- 至少編輯一個(gè)設(shè)備、桶面殖、規(guī)則竖哩;
- 重編譯 CRUSH Map;
- 注入 CRUSH Map脊僚。
要激活 CRUSH Map 里某存儲(chǔ)池的規(guī)則相叁,找到通用規(guī)則集編號(hào)遵绰,然后把它指定到那個(gè)規(guī)則集。
2.1 獲取 CRUSH Map
要獲取集群的 CRUSH Map增淹,執(zhí)行命令:
ceph osd getcrushmap -o {compiled-crushmap-filename}
Ceph 將把 CRUSH 輸出( -o )到你指定的文件椿访,由于 CRUSH Map 是已編譯的,所以編輯前必須先反編譯虑润。
2.2 反編譯 CRUSH Map
要反編譯 CRUSH Map成玫,執(zhí)行命令:
crushtool -d {compiled-crushmap-filename} -o {decompiled-crushmap-filename}
Ceph 將反編譯( -d )二進(jìn)制 CRUSH Map,且輸出( -o )到你指定的文件拳喻。
2.3 編譯 CRUSH Map
要編譯 CRUSH Map哭当,執(zhí)行命令:
crushtool -c {decompiled-crush-map-filename} -o {compiled-crush-map-filename}
Ceph 將把已編譯的 CRUSH Map 保存到你指定的文件。
2.4 注入 CRUSH Map
要把 CRUSH Map 應(yīng)用到集群冗澈,執(zhí)行命令:
ceph osd setcrushmap -i {compiled-crushmap-filename}
Ceph 將把你指定的已編譯 CRUSH Map 注入到集群钦勘。
3. CRUSH Map 參數(shù)
CRUSH Map 主要有 4 個(gè)段落。
-
設(shè)備: 由任意對(duì)象存儲(chǔ)設(shè)備組成亚亲,即對(duì)應(yīng)一個(gè)
ceph-osd
進(jìn)程的存儲(chǔ)器彻采。 Ceph 配置文件里的每個(gè) OSD 都應(yīng)該有一個(gè)設(shè)備枪孩。 -
桶類(lèi)型: 定義了 CRUSH 分級(jí)結(jié)構(gòu)里要用的桶類(lèi)型(
types
)蜂桶,桶由逐級(jí)匯聚的存儲(chǔ)位置(如行啥么、機(jī)柜佑颇、機(jī)箱低零、主機(jī)等等)及其權(quán)重組成院仿。 - 桶實(shí)例: 定義了桶類(lèi)型后饲鄙,還必須聲明主機(jī)的桶類(lèi)型感帅、以及規(guī)劃的其它故障域门扇。
- 規(guī)則: 由選擇桶的方法組成雹有。
3.1 CRUSH Map 之設(shè)備
為把 PG 映射到 OSD , CRUSH Map 需要 OSD 列表(即配置文件所定義的 OSD 守護(hù)進(jìn)程名稱)臼寄,所以它們首先出現(xiàn)在 CRUSH Map 里霸奕。要在 CRUSH Map 里聲明一個(gè)設(shè)備,在設(shè)備列表后面新建一行吉拳,輸入 device
质帅、之后是唯一的數(shù)字 ID 、之后是相應(yīng)的 ceph-osd
守護(hù)進(jìn)程實(shí)例名字留攒。
# devices
device {num} {osd.name}
例如:
# devices
device 0 osd.0
device 1 osd.1
device 2 osd.2
device 3 osd.3
3.2 CRUSH Map 之桶類(lèi)型
CRUSH Map 里的第二個(gè)列表定義了 bucket (桶)類(lèi)型煤惩,桶簡(jiǎn)化了節(jié)點(diǎn)和葉子層次。節(jié)點(diǎn)(或非葉子)桶在分級(jí)結(jié)構(gòu)里一般表示物理位置炼邀,節(jié)點(diǎn)匯聚了其它節(jié)點(diǎn)或葉子魄揉,葉桶表示 ceph-osd
守護(hù)進(jìn)程及其對(duì)應(yīng)的存儲(chǔ)媒體。
要往 CRUSH Map 中增加一種 bucket 類(lèi)型拭宁,在現(xiàn)有桶類(lèi)型列表下方新增一行洛退,輸入 type
瓣俯、之后是惟一數(shù)字 ID 和一個(gè)桶名。按慣例兵怯,會(huì)有一個(gè)葉子桶為 type 0
彩匕,然而你可以指定任何名字(如 osd 、 disk 媒区、 drive 驼仪、 storage 等等):
# types
type {num} {bucket-name}
例如:
# 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
3.3 CRUSH Map 之桶層次
CRUSH 算法根據(jù)各設(shè)備的權(quán)重、大致統(tǒng)一的概率把數(shù)據(jù)對(duì)象分布到存儲(chǔ)設(shè)備中袜漩。 CRUSH 根據(jù)你定義的集群運(yùn)行圖分布對(duì)象及其副本谅畅, CRUSH Map 表達(dá)了可用存儲(chǔ)設(shè)備以及包含它們的邏輯單元。
要把 PG 映射到跨故障域的 OSD 噪服,一個(gè) CRUSH Map 需定義一系列分級(jí)桶類(lèi)型(即現(xiàn)有 CRUSH Map 的 # type
下)。創(chuàng)建桶分級(jí)結(jié)構(gòu)的目的是按故障域隔離葉子節(jié)點(diǎn)胜茧,像主機(jī)粘优、機(jī)箱、機(jī)柜呻顽、電力分配單元雹顺、機(jī)群、行廊遍、房間嬉愧、和數(shù)據(jù)中心。除了表示葉子節(jié)點(diǎn)的 OSD 喉前,其它分級(jí)結(jié)構(gòu)都是任意的没酣,你可以按需定義。
聲明一個(gè)桶實(shí)例時(shí)卵迂,你必須指定其類(lèi)型裕便、惟一名稱(字符串)、惟一負(fù)整數(shù) ID (可選)见咒、指定和各條目總?cè)萘?能力相關(guān)的權(quán)重偿衰、指定桶算法(通常是 straw )、和哈希(通常為 0 改览,表示哈希算法 rjenkins1 )下翎。一個(gè)桶可以包含一到多個(gè)條目,這些條目可以由節(jié)點(diǎn)桶或葉子組成宝当,它們可以有個(gè)權(quán)重用來(lái)反映條目的相對(duì)權(quán)重视事。
你可以按下列語(yǔ)法聲明一個(gè)節(jié)點(diǎn)桶:
[bucket-type] [bucket-name] {
id [a unique negative numeric ID]
weight [the relative capacity/capability of the item(s)]
alg [the bucket type: uniform | list | tree | straw ]
hash [the hash type: 0 by default]
item [item-name] weight [weight]
}
例如,我們可以定義兩個(gè)主機(jī)桶和一個(gè)機(jī)柜桶庆揩,機(jī)柜桶包含兩個(gè)主機(jī)桶郑口, OSD 被聲明為主機(jī)桶內(nèi)的條目:
host node1 {
id -1
alg straw
hash 0
item osd.0 weight 1.00
item osd.1 weight 1.00
}
host node2 {
id -2
alg straw
hash 0
item osd.2 weight 1.00
item osd.3 weight 1.00
}
rack rack1 {
id -3
alg straw
hash 0
item node1 weight 2.00
item node2 weight 2.00
}
調(diào)整桶的權(quán)重
Ceph 用雙精度類(lèi)型數(shù)據(jù)表示桶權(quán)重鸳碧。權(quán)重和設(shè)備容量不同,我們建議用 1.00 作為 1TB 存儲(chǔ)設(shè)備的相對(duì)權(quán)重犬性,這樣 0.5 的權(quán)重大概代表 500GB 瞻离、 3.00 大概代表 3TB 。較高級(jí)桶的權(quán)重是所有葉子桶的權(quán)重之和乒裆。
一個(gè)桶的權(quán)重是一維的套利,你也可以計(jì)算條目權(quán)重來(lái)反映存儲(chǔ)設(shè)備性能。例如鹤耍,如果你有很多 1TB 的硬盤(pán)肉迫,其中一些數(shù)據(jù)傳輸速率相對(duì)低、其他的數(shù)據(jù)傳輸率相對(duì)高稿黄,即使它們?nèi)萘肯嗤吧溃矐?yīng)該設(shè)置不同的權(quán)重(如給吞吐量較低的硬盤(pán)設(shè)置權(quán)重 0.8 ,較高的設(shè)置 1.20 )杆怕。
3.4 CRUSH Map 之規(guī)則
CRUSH Map 支持“ CRUSH 規(guī)則”的概念族购,用以確定一個(gè)存儲(chǔ)池里數(shù)據(jù)的分布。CRUSH 規(guī)則定義了歸置和復(fù)制策略陵珍、或分布策略寝杖,用它可以規(guī)定 CRUSH 如何放置對(duì)象副本。對(duì)大型集群來(lái)說(shuō)互纯,你可能創(chuàng)建很多存儲(chǔ)池瑟幕,且每個(gè)存儲(chǔ)池都有它自己的 CRUSH 規(guī)則集和規(guī)則。默認(rèn)的 CRUSH Map 里留潦,每個(gè)存儲(chǔ)池有一條規(guī)則只盹、一個(gè)規(guī)則集被分配到每個(gè)默認(rèn)存儲(chǔ)池。
注意: 大多數(shù)情況下兔院,你都不需要修改默認(rèn)規(guī)則鹿霸。新創(chuàng)建存儲(chǔ)池的默認(rèn)規(guī)則集是 0
。
規(guī)則格式如下:
rule <rulename> {
ruleset <ruleset>
type [ replicated | erasure ]
min_size <min-size>
max_size <max-size>
step take <bucket-type>
step [choose|chooseleaf] [firstn|indep] <N> <bucket-type>
step emit
}
參數(shù)說(shuō)明:
-
ruleset
:區(qū)分一條規(guī)則屬于某個(gè)規(guī)則集的手段秆乳。給存儲(chǔ)池設(shè)置規(guī)則集后激活懦鼠。 -
type
:規(guī)則類(lèi)型,目前僅支持replicated
和erasure
屹堰,默認(rèn)是replicated
肛冶。 -
min_size
:可以選擇此規(guī)則的存儲(chǔ)池最小副本數(shù)。 -
max_size
:可以選擇此規(guī)則的存儲(chǔ)池最大副本數(shù)扯键。 -
step take <bucket-name>
:選取起始的桶名睦袖,并迭代到樹(shù)底。 -
step choose firstn {num} type {bucket-type}
:選取指定類(lèi)型桶的數(shù)量荣刑,這個(gè)數(shù)字通常是存儲(chǔ)池的副本數(shù)(即 pool size )馅笙。如果{num} == 0
伦乔, 選擇pool-num-replicas
個(gè)桶(所有可用的);如果{num} > 0 && < pool-num-replicas
董习,就選擇那么多的桶烈和;如果{num} < 0
,它意味著選擇pool-num-replicas - {num}
個(gè)桶皿淋。 -
step chooseleaf firstn {num} type {bucket-type}
:選擇{bucket-type}
類(lèi)型的桶集合招刹,并從各桶的子樹(shù)里選擇一個(gè)葉子節(jié)點(diǎn)。桶集合的數(shù)量通常是存儲(chǔ)池的副本數(shù)(即 pool size )窝趣。如果{num} == 0
疯暑,選擇pool-num-replicas
個(gè)桶(所有可用的);如果{num} > 0 && < pool-num-replicas
哑舒,就選擇那么多的桶妇拯;如果{num} < 0
,它意味著選擇pool-num-replicas - {num}
個(gè)桶洗鸵。 -
step emit
:輸出當(dāng)前值并清空堆棧越锈。通常用于規(guī)則末尾,也適用于相同規(guī)則應(yīng)用到不同樹(shù)的情況预麸。
4. 主親和性
某個(gè) Ceph 客戶端讀寫(xiě)數(shù)據(jù)時(shí),總是連接 acting set 里的主 OSD (如 [2, 3, 4]
中儒将, osd.2
是主的)吏祸。有時(shí)候某個(gè) OSD 與其它的相比并不適合做主 OSD (比如其硬盤(pán)慢、或控制器慢)钩蚊。最大化硬件利用率時(shí)為防止性能瓶頸(特別是讀操作)贡翘,你可以調(diào)整 OSD 的主親和性,這樣 CRUSH 就盡量不把它用作 acting set 里的主 OSD 了砰逻。
ceph osd primary-affinity <osd-id> <weight>
主親和性默認(rèn)為 1
(就是說(shuō)此 OSD 可作為主 OSD )鸣驱。此值合法范圍為 0-1
,其中 0
意為此 OSD 不能用作主的蝠咆, 1
意為 OSD 可用作主的踊东。此權(quán)重 < 1
時(shí), CRUSH 選擇主 OSD 時(shí)選中它的可能性就較低刚操。
5. 增加/移動(dòng) OSD
要增加或移動(dòng)在線集群里 OSD 所對(duì)應(yīng)的 CRUSH Map 條目闸翅,執(zhí)行 ceph osd crush set 命令。
ceph osd crush set {id-or-name} {weight} {bucket-type}={bucket-name} [{bucket-type}={bucket-name} ...]
6. 調(diào)整 OSD 的 CRUSH 權(quán)重
要調(diào)整在線集群中某個(gè) OSD 的 CRUSH 權(quán)重菊霜,執(zhí)行命令:
ceph osd crush reweight {name} {weight}
7. 刪除 OSD
要從在線集群里把某個(gè) OSD 徹底踢出 CRUSH Map坚冀,或僅踢出某個(gè)指定位置的 OSD,執(zhí)行命令:
ceph osd crush remove {name} {<ancestor>}
8. 增加桶
要在運(yùn)行集群的 CRUSH Map 中新建一個(gè)桶鉴逞,用 ceph osd crush add-bucket 命令:
ceph osd crush add-bucket {bucket-name} {bucket-type}
9. 移動(dòng)桶
要把一個(gè)桶移動(dòng)到 CRUSH Map 里的不同位置记某,執(zhí)行命令:
ceph osd crush move {bucket-name} {bucket-type}={bucket-name} [{bucket-type}={bucket-name} ...]
10. 刪除桶
要把一個(gè)桶從 CRUSH Map 的分級(jí)結(jié)構(gòu)中刪除司训,可用此命令:
ceph osd crush remove {bucket-name}
注意:從 CRUSH 分級(jí)結(jié)構(gòu)里刪除時(shí)必須是空桶。
11. 可調(diào)選項(xiàng)
從 v0.74 起液南,如果 CRUSH 可調(diào)選項(xiàng)不是最優(yōu)值( v0.73 版里的默認(rèn)值) Ceph 就會(huì)發(fā)出健康告警壳猜,有兩種方法可消除這些告警:
1、調(diào)整現(xiàn)有集群上的可調(diào)選項(xiàng)贺拣。注意蓖谢,這可能會(huì)導(dǎo)致一些數(shù)據(jù)遷移(可能有 10% 之多)。這是推薦的辦法譬涡,但是在生產(chǎn)集群上要注意此調(diào)整對(duì)性能帶來(lái)的影響闪幽。此命令可啟用較優(yōu)可調(diào)選項(xiàng):
ceph osd crush tunables optimal
如果切換得不太順利(如負(fù)載太高)且切換才不久,或者有客戶端兼容問(wèn)題(較老的 cephfs 內(nèi)核驅(qū)動(dòng)或 rbd 客戶端涡匀、或早于 bobtail 的 librados 客戶端)盯腌,你可以這樣切回:
ceph osd crush tunables legacy
2、不對(duì) CRUSH 做任何更改也能消除報(bào)警陨瘩,把下列配置加入 ceph.conf
的 [mon]
段下:
mon warn on legacy crush tunables = false
為使變更生效需重啟所有監(jiān)視器腕够,或者執(zhí)行下列命令:
ceph tell mon.\* injectargs --no-mon-warn-on-legacy-crush-tunables
5.7 CRUSH Map 實(shí)例
假設(shè)你想讓大多數(shù)存儲(chǔ)池映射到使用大容量硬盤(pán)的 OSD 上,但是其中一些存儲(chǔ)池映射到使用高速 SSD 的 OSD 上舌劳。在同一個(gè) CRUSH Map 內(nèi)有多個(gè)獨(dú)立的 CRUSH 層級(jí)結(jié)構(gòu)是可能的帚湘,定義兩棵樹(shù)、分別有自己的根節(jié)點(diǎn) —— 一個(gè)用于機(jī)械硬盤(pán)(如 root platter )甚淡、一個(gè)用于 SSD (如 root ssd )大诸,具體的 CRUSH Map 內(nèi)容如下:
# devices
device 0 osd.0
device 1 osd.1
device 2 osd.2
device 3 osd.3
device 4 osd.4
device 5 osd.5
device 6 osd.6
device 7 osd.7
# types
type 0 osd
type 1 host
type 2 root
# buckets
host ceph-osd-ssd-server-1 {
id -1
alg straw
hash 0
item osd.0 weight 1.00
item osd.1 weight 1.00
}
host ceph-osd-ssd-server-2 {
id -2
alg straw
hash 0
item osd.2 weight 1.00
item osd.3 weight 1.00
}
host ceph-osd-platter-server-1 {
id -3
alg straw
hash 0
item osd.4 weight 1.00
item osd.5 weight 1.00
}
host ceph-osd-platter-server-2 {
id -4
alg straw
hash 0
item osd.6 weight 1.00
item osd.7 weight 1.00
}
root platter {
id -5
alg straw
hash 0
item ceph-osd-platter-server-1 weight 2.00
item ceph-osd-platter-server-2 weight 2.00
}
root ssd {
id -6
alg straw
hash 0
item ceph-osd-ssd-server-1 weight 2.00
item ceph-osd-ssd-server-2 weight 2.00
}
# rules
rule replicated_ruleset {
ruleset 0
type replicated
min_size 1
max_size 10
step take default
step chooseleaf firstn 0 type host
step emit
}
rule platter {
ruleset 1
type replicated
min_size 0
max_size 10
step take platter
step chooseleaf firstn 0 type host
step emit
}
rule ssd {
ruleset 2
type replicated
min_size 0
max_size 4
step take ssd
step chooseleaf firstn 0 type host
step emit
}
rule ssd-primary {
ruleset 3
type replicated
min_size 5
max_size 10
step take ssd
step chooseleaf firstn 1 type host
step emit
step take platter
step chooseleaf firstn -1 type host
step emit
}
然后你可以設(shè)置一個(gè)存儲(chǔ)池,讓它使用 SSD 規(guī)則:
ceph osd pool set <poolname> crush_ruleset 2
同樣贯卦,用 ssd-primary
規(guī)則將使存儲(chǔ)池內(nèi)的各歸置組用 SSD 作主 OSD 资柔,普通硬盤(pán)作副本。