1. 介紹
CRUSH 算法通過計算資料存儲位置來确定如何存儲和檢索。 CRUSH 授權 Ceph 用戶端直接連接配接 OSD ,而非通過一個中央伺服器或代理。資料存儲、檢索算法的使用,使 Ceph 避免了單點故障、性能瓶頸、和伸縮的實體限制。
CRUSH 需要一張叢集的 Map,且使用 CRUSH Map 把資料僞随機地、盡量平均地分布到整個叢集的 OSD 裡。CRUSH Map 包含 OSD 清單、把裝置彙聚為實體位置的“桶”清單、和訓示 CRUSH 如何複制存儲池裡的資料的規則清單。
完全手動管理 CRUSH Map 也是可能的,在配置檔案中設定:
osd crush update on start = false
複制
2. 編輯 CRUSH Map
要編輯現有的 CRUSH Map:
- 擷取 CRUSH Map;
- 反編譯 CRUSH 圖;
- 至少編輯一個裝置、桶、規則;
- 重編譯 CRUSH Map;
- 注入 CRUSH Map。
要激活 CRUSH Map 裡某存儲池的規則,找到通用規則集編号,然後把它指定到那個規則集。
2.1 擷取 CRUSH Map
要擷取叢集的 CRUSH Map,執行指令:
ceph osd getcrushmap -o {compiled-crushmap-filename}
複制
Ceph 将把 CRUSH 輸出( -o )到你指定的檔案,由于 CRUSH Map 是已編譯的,是以編輯前必須先反編譯。
2.2 反編譯 CRUSH Map
要反編譯 CRUSH Map,執行指令:
crushtool -d {compiled-crushmap-filename} -o {decompiled-crushmap-filename}
複制
Ceph 将反編譯( -d )二進制 CRUSH Map,且輸出( -o )到你指定的檔案。
2.3 編譯 CRUSH Map
要編譯 CRUSH Map,執行指令:
crushtool -c {decompiled-crush-map-filename} -o {compiled-crush-map-filename}
複制
Ceph 将把已編譯的 CRUSH Map 儲存到你指定的檔案。
2.4 注入 CRUSH Map
要把 CRUSH Map 應用到叢集,執行指令:
ceph osd setcrushmap -i {compiled-crushmap-filename}
複制
Ceph 将把你指定的已編譯 CRUSH Map 注入到叢集。
3. CRUSH Map 參數
CRUSH Map 主要有 4 個段落。
- 裝置: 由任意對象儲存設備組成,即對應一個
程序的存儲器。 Ceph 配置檔案裡的每個 OSD 都應該有一個裝置。ceph-osd
- 桶類型: 定義了 CRUSH 分級結構裡要用的桶類型(
),桶由逐級彙聚的存儲位置(如行、機櫃、機箱、主機等等)及其權重組成。types
- 桶執行個體: 定義了桶類型後,還必須聲明主機的桶類型、以及規劃的其它故障域。
- 規則: 由選擇桶的方法組成。
3.1 CRUSH Map 之裝置
為把 PG 映射到 OSD , CRUSH Map 需要 OSD 清單(即配置檔案所定義的 OSD 守護程序名稱),是以它們首先出現在 CRUSH Map 裡。要在 CRUSH Map 裡聲明一個裝置,在裝置清單後面建立一行,輸入
device
、之後是唯一的數字 ID 、之後是相應的
ceph-osd
守護程序執行個體名字。
# 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 之桶類型
CRUSH Map 裡的第二個清單定義了 bucket (桶)類型,桶簡化了節點和葉子層次。節點(或非葉子)桶在分級結構裡一般表示實體位置,節點彙聚了其它節點或葉子,葉桶表示
ceph-osd
守護程序及其對應的存儲媒體。
要往 CRUSH Map 中增加一種 bucket 類型,在現有桶類型清單下方新增一行,輸入
type
、之後是惟一數字 ID 和一個桶名。按慣例,會有一個葉子桶為
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 算法根據各裝置的權重、大緻統一的機率把資料對象分布到儲存設備中。 CRUSH 根據你定義的叢集運作圖分布對象及其副本, CRUSH Map 表達了可用儲存設備以及包含它們的邏輯單元。
要把 PG 映射到跨故障域的 OSD ,一個 CRUSH Map 需定義一系列分級桶類型(即現有 CRUSH Map 的
# type
下)。建立桶分級結構的目的是按故障域隔離葉子節點,像主機、機箱、機櫃、電力配置設定單元、機群、行、房間、和資料中心。除了表示葉子節點的 OSD ,其它分級結構都是任意的,你可以按需定義。
聲明一個桶執行個體時,你必須指定其類型、惟一名稱(字元串)、惟一負整數 ID (可選)、指定和各條目總容量/能力相關的權重、指定桶算法(通常是 straw )、和哈希(通常為 0 ,表示雜湊演算法 rjenkins1 )。一個桶可以包含一到多個條目,這些條目可以由節點桶或葉子組成,它們可以有個權重用來反映條目的相對權重。
你可以按下列文法聲明一個節點桶:
[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]
}
複制
例如,我們可以定義兩個主機桶和一個機櫃桶,機櫃桶包含兩個主機桶, OSD 被聲明為主機桶内的條目:
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
}
複制
調整桶的權重
Ceph 用雙精度類型資料表示桶權重。權重和裝置容量不同,我們建議用 1.00 作為 1TB 儲存設備的相對權重,這樣 0.5 的權重大概代表 500GB 、 3.00 大概代表 3TB 。較進階桶的權重是所有葉子桶的權重之和。
一個桶的權重是一維的,你也可以計算條目權重來反映儲存設備性能。例如,如果你有很多 1TB 的硬碟,其中一些資料傳輸速率相對低、其他的資料傳輸率相對高,即使它們容量相同,也應該設定不同的權重(如給吞吐量較低的硬碟設定權重 0.8 ,較高的設定 1.20 )。
3.4 CRUSH Map 之規則
CRUSH Map 支援“ CRUSH 規則”的概念,用以确定一個存儲池裡資料的分布。CRUSH 規則定義了歸置和複制政策、或分布政策,用它可以規定 CRUSH 如何放置對象副本。對大型叢集來說,你可能建立很多存儲池,且每個存儲池都有它自己的 CRUSH 規則集和規則。預設的 CRUSH Map 裡,每個存儲池有一條規則、一個規則集被配置設定到每個預設存儲池。
注意: 大多數情況下,你都不需要修改預設規則。新建立存儲池的預設規則集是
。
規則格式如下:
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
}
複制
參數說明:
-
:區分一條規則屬于某個規則集的手段。給存儲池設定規則集後激活。ruleset
-
:規則類型,目前僅支援type
和replicated
,預設是erasure
。replicated
-
:可以選擇此規則的存儲池最小副本數。min_size
-
:可以選擇此規則的存儲池最大副本數。max_size
-
:選取起始的桶名,并疊代到樹底。step take <bucket-name>
-
:選取指定類型桶的數量,這個數字通常是存儲池的副本數(即 pool size )。如果step choose firstn {num} type {bucket-type}
, 選擇{num} == 0
個桶(所有可用的);如果pool-num-replicas
,就選擇那麼多的桶;如果{num} > 0 && < pool-num-replicas
,它意味着選擇{num} < 0
個桶。pool-num-replicas - {num}
-
:選擇step chooseleaf firstn {num} type {bucket-type}
類型的桶集合,并從各桶的子樹裡選擇一個葉子節點。桶集合的數量通常是存儲池的副本數(即 pool size )。如果{bucket-type}
,選擇{num} == 0
個桶(所有可用的);如果pool-num-replicas
,就選擇那麼多的桶;如果{num} > 0 && < pool-num-replicas
,它意味着選擇{num} < 0
個桶。pool-num-replicas - {num}
-
:輸出目前值并清空堆棧。通常用于規則末尾,也适用于相同規則應用到不同樹的情況。step emit
4. 主親和性
某個 Ceph 用戶端讀寫資料時,總是連接配接 acting set 裡的主 OSD (如
[2, 3, 4]
中,
osd.2
是主的)。有時候某個 OSD 與其它的相比并不适合做主 OSD (比如其硬碟慢、或控制器慢)。最大化硬體使用率時為防止性能瓶頸(特别是讀操作),你可以調整 OSD 的主親和性,這樣 CRUSH 就盡量不把它用作 acting set 裡的主 OSD 了。
ceph osd primary-affinity <osd-id> <weight>
複制
主親和性預設為
1
(就是說此 OSD 可作為主 OSD )。此值合法範圍為
0-1
,其中
意為此 OSD 不能用作主的,
1
意為 OSD 可用作主的。此權重
< 1
時, CRUSH 選擇主 OSD 時選中它的可能性就較低。
5. 增加/移動 OSD
要增加或移動線上叢集裡 OSD 所對應的 CRUSH Map 條目,執行 ceph osd crush set 指令。
ceph osd crush set {id-or-name} {weight} {bucket-type}={bucket-name} [{bucket-type}={bucket-name} ...]
複制
6. 調整 OSD 的 CRUSH 權重
要調整線上叢集中某個 OSD 的 CRUSH 權重,執行指令:
ceph osd crush reweight {name} {weight}
複制
7. 删除 OSD
要從線上叢集裡把某個 OSD 徹底踢出 CRUSH Map,或僅踢出某個指定位置的 OSD,執行指令:
ceph osd crush remove {name} {<ancestor>}
複制
8. 增加桶
要在運作叢集的 CRUSH Map 中建立一個桶,用 ceph osd crush add-bucket 指令:
ceph osd crush add-bucket {bucket-name} {bucket-type}
複制
9. 移動桶
要把一個桶移動到 CRUSH Map 裡的不同位置,執行指令:
ceph osd crush move {bucket-name} {bucket-type}={bucket-name} [{bucket-type}={bucket-name} ...]
複制
10. 删除桶
要把一個桶從 CRUSH Map 的分級結構中删除,可用此指令:
ceph osd crush remove {bucket-name}
複制
注意:從 CRUSH 分級結構裡删除時必須是空桶。
11. 可調選項
從 v0.74 起,如果 CRUSH 可調選項不是最優值( v0.73 版裡的預設值) Ceph 就會發出健康告警,有兩種方法可消除這些告警:
1、調整現有叢集上的可調選項。注意,這可能會導緻一些資料遷移(可能有 10% 之多)。這是推薦的辦法,但是在生産叢集上要注意此調整對性能帶來的影響。此指令可啟用較優可調選項:
ceph osd crush tunables optimal
複制
如果切換得不太順利(如負載太高)且切換才不久,或者有用戶端相容問題(較老的 cephfs 核心驅動或 rbd 用戶端、或早于 bobtail 的 librados 用戶端),你可以這樣切回:
ceph osd crush tunables legacy
複制
2、不對 CRUSH 做任何更改也能消除報警,把下列配置加入
ceph.conf
的
[mon]
段下:
mon warn on legacy crush tunables = false
複制
為使變更生效需重新開機所有螢幕,或者執行下列指令:
ceph tell mon.\* injectargs --no-mon-warn-on-legacy-crush-tunables
複制
5.7 CRUSH Map 執行個體
假設你想讓大多數存儲池映射到使用大容量硬碟的 OSD 上,但是其中一些存儲池映射到使用高速 SSD 的 OSD 上。在同一個 CRUSH Map 内有多個獨立的 CRUSH 層級結構是可能的,定義兩棵樹、分别有自己的根節點 —— 一個用于機械硬碟(如 root platter )、一個用于 SSD (如 root ssd ),具體的 CRUSH Map 内容如下:
# 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
}
複制
然後你可以設定一個存儲池,讓它使用 SSD 規則:
ceph osd pool set <poolname> crush_ruleset 2
複制
同樣,用
ssd-primary
規則将使存儲池内的各歸置組用 SSD 作主 OSD ,普通硬碟作副本。