Ceph の CRUSH マップの書き方

作成日:2012.02.11
更新日:2013.05.03

このページでは ceph の CRUSH マップの記述方法を説明する。 Ceph の設定手順の中では「Ceph を使ってみる」のSTEP7で必要になる。

以下は関連ページ。


更新履歴
(2012.02.11) 作成。
(2012.02.14) 「CRUSHマップの取得・設定」と「テストツールを使った配置テスト」を追記。
(2012.04.02) 稼働中の CRUSH マップの確認方法を追加。
(2012.05.03) CRUSH マップの記述ルールを追加。


目次

CRUSHマップの取得・設定

稼働中の ceph システムから CRUSH マップを取得し、再設定するには以下の手順が必要である。

まず CRUSH マップを /tmp/crush というファイルに書き出す。

# ceph osd getcrushmap -o /tmp/crush

/tmp/crush はバイナリファイルのため、これを人間が見て分かるテキストファイルにデコードする。 変換後のファイルが /tmp/crush.txt になる。

crushtool -d /tmp/crush -o /tmp/crush.txt

逆に /tmp/crush.txt から元のバイナリファイルにエンコードするには以下のようにする。 結果は /tmp/crush.new に書き出される。

# crushtool -c /tmp/crush.txt -o /tmp/crush.new

バイナリ形式の CRUSH マップを稼働中の ceph システムに適用するには以下のようにする。

# ceph osd setcrushmap -i /tmp/crush.new

ただし CRUSH マップを適用しただけでは、すぐにオブジェクトが CRUSH マップに従った配置にならない。 これを正すには reweight を行う。

# ceph -w

構造

まず CRUSH マップの例を示す。

これは ceph 0.39 で mkcephfs を実行したときにできた CRUSH マップである。 ceph.conf の中で定義された OSD を同一のホストに属するもの同士で一つにまとめるため実質2段の階層となっている。

ただし以前のバージョンの ceph は、ceph.conf に定義された全ての OSD を一まとめにした実質1段の階層だった。同一構成であっても ceph のバージョンによって異なる CRUSH マップができる可能性がある。

# 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
device 8 osd.8
device 9 osd.9
device 10 osd.10
device 11 osd.11

# types
type 0 osd
type 1 host
type 2 rack
type 3 pool

# buckets
host host9 {
	id -2		# do not change unnecessarily
	# weight 4.000
	alg straw
	hash 0	# rjenkins1
	item osd.0 weight 1.000
	item osd.1 weight 1.000
	item osd.2 weight 1.000
	item osd.3 weight 1.000
}
host host12 {
	id -4		# do not change unnecessarily
	# weight 4.000
	alg straw
	hash 0	# rjenkins1
	item osd.10 weight 1.000
	item osd.11 weight 1.000
	item osd.8 weight 1.000
	item osd.9 weight 1.000
}
host host11 {
	id -5		# do not change unnecessarily
	# weight 4.000
	alg straw
	hash 0	# rjenkins1
	item osd.4 weight 1.000
	item osd.5 weight 1.000
	item osd.6 weight 1.000
	item osd.7 weight 1.000
}
rack unknownrack {
	id -3		# do not change unnecessarily
	# weight 12.000
	alg straw
	hash 0	# rjenkins1
	item host9 weight 4.000
	item host12 weight 4.000
	item host11 weight 4.000
}
pool default {
	id -1		# do not change unnecessarily
	# weight 12.000
	alg straw
	hash 0	# rjenkins1
	item unknownrack weight 12.000
}

# rules
rule data {
	ruleset 0
	type replicated
	min_size 1
	max_size 10
	step take default
	step chooseleaf firstn 0 type host
	step emit
}

rule metadata {
	ruleset 1
	type replicated
	min_size 1
	max_size 10
	step take default
	step chooseleaf firstn 0 type host
	step emit
}

rule rbd {
	ruleset 2
	type replicated
	min_size 1
	max_size 10
	step take default
	step chooseleaf firstn 0 type host
	step emit
}

CRUSH マップはセクションに分かれてはいないが、ある程度意味的なまとまりがある。 順番に説明する。

Devices

まず先頭にある device は OSD のことである。 ceph.conf で記述している OSD を一つづつ device として定義してゆく。

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

Types

types は CRUSH マップの bucket に与える型の名前である。 type の名前(青字)には意味はなく適当につけてよい。 ただし慣習として poolosd を定義しておいた方がよいと思われる。 type の番号は bucket の階層構造とは無関係である。 type 名毎に重ならないように順番に番号を振る。

# types
type 0 osd
type 1 host
type 2 rack
type 3 pool

Buckets

次に bucket の定義を記述する。 青字の部分は type で定義した bucket 型の名前を指定し、次に bucket の名前を付ける。 この下の例では rack 型の bucket unknownrack ということになる。 名前は自由につけてよい。

ここで定義するのは bucket 内にある item と個数だけであり、この段でレプリケーションをどう配分するかはルール(rule)の方で記述する。

# buckets
rack unknownrack {
	id -3		# do not change unnecessarily
	# weight 12.000
	alg straw
	hash 0	# rjenkins1
	item host9 weight 4.000
	item host12 weight 4.000
	item host11 weight 4.000
}

Rules

ルールは CRUSH の選択ルールを記述する。 RADOS の pool の数だけルールを記述する必要がある。 また pool 毎に別のルールを記述できるので、pool によって使われる OSDを変えたりすることもできる。

rule data {
	ruleset 0
	type replicated
	min_size 1
	max_size 10

	step take default                # L1
	step choose firstn 0 type host   # L2
        step choose firstn 1 type device # L3
	step emit
}

まずルールのうち形式的な部分から説明する。

次にステップの部分の説明をする。

いうまでもなくルールの最後は device を選択して終了する必要がある。 そのため L3 のルールはある意味不必要である。 L2 の選択後は device を見つけるところまで選択せよという意味で choose のかわりに chooseleaf が用意されている。 以下の1行は L2 と L3 を合わせた意味を持つ。

	step chooseleaf firstn 0 type host

なお chooseleaf にも firstn の替わりに indep を指定する方法がある。 これもどのような効果があるか分からない。

	step chooseleaf indep 0 type host

注意事項

いくつか注意事項を記述する。

正式なドキュメントが存在しないためルールなのかどうかはっきりしないが、以下のようなマナーを守ったほうがよい。

テストツールを使った配置テスト

crushtool コマンドを使うことで CRUSH マップを実際の ceph システムに適用する前に、OSD 間にオブジェクトがどのように割り付けられるかを模擬することができる。

2012/05/07
Ceph-0.43 で確認すると、この機能は失われて、crushtool --test の結果は別の表示結果を返すようになっている。

8つの OSD が straw 型の bucket によって均等に重み付けされているとする。

host ceph1 {
        id -2           # do not change unnecessarily
        # weight 3.000
        alg straw
        hash 0  # rjenkins1
        item osd.0 weight 1.000
        item osd.1 weight 1.000
        item osd.2 weight 1.000
        item osd.3 weight 1.000
        item osd.4 weight 1.000
        item osd.5 weight 1.000
        item osd.6 weight 1.000
        item osd.7 weight 1.000
}
(これは CRUSH マップの一部)

これを実行するためにはテキスト形式の CRUSH マップをバイナリ形式に変換する。

# crushtool -c (テキスト形式のクラッシュマップ) -o /tmp/crush.bin.new

crushtool は --test を使うとオブジェクトの配置実験ができる。 デフォルトでは 10,000 個のオブジェクトを割り付けた時に各 OSD にどのようにマップされるかが示される。 --rule を指定すると特定のルールのみをテスト、--num_rep を指定するとレプリケーションの多重度を設定できる。

# crushtool -i /tmp/crush.bin.new --rule 0 --num_rep 2 --test
devices weights (hex): [10000,10000,10000,10000,10000,10000,10000,10000]
rule 0 (data), x = 0..9999
 device 0:      2525
 device 1:      2513
 device 2:      2529
 device 3:      2536
 device 4:      2453
 device 5:      2507
 device 6:      2489
 device 7:      2448
 result size 2x:        10000

ほぼ均等になっているのが分かる。

次に 8 個の OSD の weight を傾けてみる。

host ceph1 {
        id -2           # do not change unnecessarily
        # weight 3.000
        alg straw
        hash 0  # rjenkins1
        item osd.0 weight 0.000
        item osd.1 weight 0.062
        item osd.2 weight 0.125
        item osd.3 weight 0.250
        item osd.4 weight 0.500
        item osd.5 weight 1.000
        item osd.6 weight 2.000
        item osd.7 weight 4.000
}
(これは CRUSH マップの一部)

この結果は以下のようになる。 weight の数値は倍々にしたがオブジェクトの割り付け量は倍々になっていない。 また weight に 0.000 を指定しても多少オブジェクトが割り付けられる。

# crushtool -i /tmp/crush.bin.new --rule 0 --num_rep 2 --test
devices weights (hex): [10000,10000,10000,10000,10000,10000,10000,10000]
rule 0 (data), x = 0..9999
 device 0:      6
 device 1:      355
 device 2:      574
 device 3:      1088
 device 4:      1915
 device 5:      3267
 device 6:      5398
 device 7:      7397
 result size 2x:        10000

稼働中の CRUSH マップの確認

Ceph が稼働中動作した後に CRUSH マップを確認するには ceph osd tree を使うとよい。 CRUSH マップの階層と重み付けが表示される。

# ceph osd tree
2012-03-09 02:00:53.036484 mon <- [osd,tree]
2012-03-09 02:00:53.036745 mon.0 -> 'dumped osdmap tree epoch 5' (0)
# id    weight  type name       up/down reweight
-1      3       pool default
-3      3               rack unknownrack
-2      1                       host host1
0       1                               osd.0   up      1
-4      1                       host host2
1       1                               osd.1   up      1
-5      1                       host host3
2       1                               osd.2   up      1

いくつか例をあげてみる。

例1

上位階層には制約を設けず、レプリケーション数分の device を選択する。

	step take default
	step choose firstn 0 type device
	step emit

この場合、同一 host の中の device が選択されることもある。

例2

まず rack の中から1つ選択肢、その rack の中からレプリケーション数分の host を選択する。 各 host からは 1 個づつ device を選択する。

	step take default
	step choose firstn 1 type rack # L1
	step choose firstn 0 type host
        step choose firstn 1 type device
	step emit

最初の step choose がない場合、host は異なる rack から選択されることもある。

コメント

トラックバック   [Trackback URL: http://www.nminoru.jp/cgi-bin/tb.cgi/unix__ceph__how-to-write-crushmap]
コメントを書き込む

TOP    掲示板    戻る
Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp