CRUSHMAP: 一个带层级的集群映射示例

本文由 Ceph中国社区-AmosG翻译,Thomas校稿 。

英文出处:CRUSHMAP : Example of a Hierarchical Cluster Map 欢迎加入 翻译小组

如何组织Crushmap里的数据并不总是一件容易的事,尤其是在要归类诸如SATA、SAS和SSD等不同类型的磁盘、又要依据地理位置分布数据的情形下。一起来看看我们可以把Crushmap层级结构设象成什么样。

以一个包含两个数据中心的分布作为简单的示例:

(模型1.1)

随着缓冲池的引入,我们可以轻易地想象添加SSD驱动器到我们的集群中的情形。以添加挂接有SSD盘的新主机到集群为例,这之后我们需要管理两种类型的磁盘。在一个只描述集群物理划分的层级中,我们最终会得到如下类型的层级:

(模型1.2)

然而,我们很快就会意识到这种配置并不允许在某个特定的池里单独的使用某种类型的磁盘。

为将这些不同类型的磁盘归类并组织Crushmap,最简单的方法仍是从root开始复制整棵树。这样一来,我们就得到了两颗入口分别是”default”(可命名为”hdd”)和”ssd”的子树。

另一个例子是在同一硬件设施上混合使用HDD和SSD(需划分每个主机):


(模型1.3)

这种情形下所存在的问题是我们已经依据驱动器的类型对整个集群进行了分割。因此,无法从任何其他入口点来选择”dc-1″或”dc-2″中的任何磁盘。比如,我们无法在不考虑磁盘类型的情况下,再定义一条规则来存储数据到特定数据中心上。
我们能做的是在root级添加另外一个入口点,这样就可访问所有驱动了:

(Model 1.4)

如果想在树中保持某种逻辑,我们可以添加更多层级,比如添加一些表示磁盘类型的逻辑以及另一些表示物理分布的逻辑。这些“逻辑”可置于任何地方且能随意命名。比如,这里我添加的名为“pool”的层级其他人可将其命名为“type”或者其他名字。


(模型1.5)

这种方法可行,但很难理解。此外,当在主机上混用SSD和HDD时就更难理解了,因为这会涉及到主机之间的复制。另外,物理数据的放置逻辑也不存在了。我们可以尝试在HOST级和OSD级间插入新的层级:

(模型1.6)

好吧!这样做在集群较小或无需再添加其它层级的情形下可能会有优势。让我们试试其他的,我们可以使用另外一种组织方式,如将OSD归类到不同的层级并应用于具体的规则。比如,用
step chooseleaf firstn 5 type host-sata来选择SATA盘,用step chooseleaf firstn 5 type host-ssd来选择SSD盘。

(模型1.7)

但这样行不通。事实上,crush算法会尝试在每个子树中选择一个OSD。如果没找到,会尝试回溯。但这个操作相当随机,很容易以副本不足而告终。

用下面的crushmap来测试这种情况:

  • 其中一条规则是:从每个DC上选取一个SSD
  • 另外一条规则是:从每个DC上选取一个SATA
  • 还有一条规则是:从两台不同的主机上选取一个SATA

# begin crush map

tunable choose_local_tries 0

tunable choose_local_fallback_tries 0

tunable choose_total_tries 50

tunable chooseleaf_descend_once 0

tunable chooseleaf_vary_r 0

# 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

device 12 osd.12

device 13 osd.13

device 14 osd.14

device 15 osd.15

device 16 osd.16

device 17 osd.17

device 18 osd.18

# types
type 0 osd

type 1 host-ssd

type 2 host-sata

type 3 datacenter

type 4 root

# buckets
host-sata host-01 {

alg straw

hash 0

item osd.1 weight 1.000

item osd.2 weight 1.000

item osd.3 weight 1.000

}

host-sata host-02 {

alg straw

hash 0

item osd.4 weight 1.000

item osd.5 weight 1.000

item osd.6 weight 1.000

}

host-sata host-03 {

alg straw

hash 0

item osd.7 weight 1.000

item osd.8 weight 1.000

item osd.9 weight 1.000

}

host-sata host-04 {

alg straw

hash 0

item osd.10 weight 1.000

item osd.11 weight 1.000

item osd.12 weight 1.000

}

host-ssd host-05 {

alg straw

hash 0

item osd.13 weight 1.000

item osd.14 weight 1.000

item osd.15 weight 1.000

}

host-ssd host-06 {

alg straw

hash 0

item osd.16 weight 1.000

item osd.17 weight 1.000

item osd.18 weight 1.000

}

datacenter dc1 {

alg straw

hash 0

item host-01 weight 1.000

item host-02 weight 1.000

item host-05 weight 1.000

}

datacenter dc2 {

alg straw

hash 0

item host-03 weight 1.000

item host-04 weight 1.000

item host-06 weight 1.000

}

root default {

alg straw

hash 0

item dc1 weight 1.000

item dc2 weight 1.000

}

# rules

rule sata-rep_2dc {

ruleset 0

type replicated

min_size 2

max_size 2

step take default

step choose firstn 0 type datacenter

step chooseleaf firstn 1 type host-sata

step emit
}

rule ssd-rep_2dc {

ruleset 1

type replicated

min_size 2

max_size 2

step take default

step choose firstn 0 type datacenter

step chooseleaf firstn 1 type host-ssd

step emit

}

rule sata-all {

ruleset 2

type replicated

min_size 2

max_size 2

step take default

step chooseleaf firstn 0 type host-sata

step emit

}

# end crush map

可采用以下命令测试这种放置:

crushtool -c crushmap.txt -o crushmap-new.bin
crushtool --test -i crushmap-new.bin --show-utilization --rule 0 --num-rep=2
crushtool --test -i crushmap-new.bin --show-choose-tries --rule 0 --num-rep=2

检查测试情况:

$ crushtool --test -i crushmap-new.bin --show-utilization  --num-rep=2 | grep ^rule
rule 0 (sata-rep_2dc), x = 0..1023, numrep = 2..2
rule 0 (sata-rep_2dc) num_rep 2 result size == 0:   117/1024
rule 0 (sata-rep_2dc) num_rep 2 result size == 1:   448/1024
rule 0 (sata-rep_2dc) num_rep 2 result size == 2:   459/1024
rule 1 (ssd-rep_2dc), x = 0..1023, numrep = 2..2
rule 1 (ssd-rep_2dc) num_rep 2 result size == 0:459/1024
rule 1 (ssd-rep_2dc) num_rep 2 result size == 1:448/1024
rule 1 (ssd-rep_2dc) num_rep 2 result size == 2:117/1024
rule 2 (sata-all), x = 0..1023, numrep = 2..2
rule 2 (sata-all) num_rep 2 result size == 0:   113/1024
rule 2 (sata-all) num_rep 2 result size == 1:   519/1024
rule 2 (sata-all) num_rep 2 result size == 2:   392/1024

对上述所有规则,在上述的测试中,都出现了部分测试样本副本数不足的情况。尤其是在驱动器数量很少的情况下(在我们的例子中是SSD)。观察选择OSD时的重试次数,我们发现增大choose_total_tries的值并没有用因为它已经最够大。

$ crushtool --test -i crushmap-new.bin --show-choose-tries --rule 0 --num-rep=2
0:  4298
1:   226
2:   130
3:59
4:38
5:11
6:10
7: 3
8: 0
9: 2
10: 1
11: 0
12: 2

$ crushtool --test -i crushmap-new.bin --show-choose-tries --rule 1 --num-rep=2
0:  2930
1:   226
2:   130
3:59
4:38
5:11
6:10
7: 3
8: 0
9: 2
10: 1
11: 0
12: 2

$ crushtool --test -i crushmap-new.bin --show-choose-tries --rule 2 --num-rep=2
0:  2542
1:52
2:12

我们可以尝试通过增加OSD的数目来测试(这样做不是很漂亮…):

  • 在sata-rep_2dc中:step chooseleaf firstn 5 type host-sata
  • 在ssd-rep_2dc中:step chooseleaf firstn 5 type host-ssd
  • 在ssd-all中:step chooseleaf firstn 15 type host-sata

$ crushtool --test -i crushmap-new.bin --show-utilization  --num-rep=2 | grep ^rule

rule 0 (sata-rep_2dc), x = 0..1023, numrep = 2..2

rule 0 (sata-rep_2dc) num_rep 2 result size == 1:   1/1024

rule 0 (sata-rep_2dc) num_rep 2 result size == 2:   1023/1024

rule 1 (ssd-rep_2dc), x = 0..1023, numrep = 2..2

rule 1 (ssd-rep_2dc) num_rep 2 result size == 0:20/1024

rule 1 (ssd-rep_2dc) num_rep 2 result size == 1:247/1024

rule 1 (ssd-rep_2dc) num_rep 2 result size == 2:757/1024

rule 2 (sata-all), x = 0..1023, numrep = 2..2

rule 2 (sata-all) num_rep 2 result size == 2:   1024/1024

效果要好一些了,我们可以看到“sata-all”规则工作的很好,相比起来,在磁盘数量较少时,副本数总是不正确。这种分布的想法虽很有吸引力,但我们会很快意识到这种想法并不可行。

如果大家尝试过此种方法,或者有高级CRUSHMAP的相关示例,我鼓励大家把它们分享出来。我对基于这些想法所做的所有尝试都很好奇。同时,最好的方法莫过于化繁为简,以满足自己的需求。在绝大多数情况下,模型1.3还是完美的。

关于CURSH算法的更多细节可参考这里: http://ceph.com/papers/weil-crush-sc06.pdf

Leave a Comment

电子邮件地址不会被公开。